Implement function attributes
This commit is contained in:
		
							parent
							
								
									1599a78d03
								
							
						
					
					
						commit
						b3eee4ae99
					
				@ -165,6 +165,7 @@ const LLVM = struct {
 | 
			
		||||
        const llvm = b.createModule(.{
 | 
			
		||||
            .target = target,
 | 
			
		||||
            .optimize = optimize,
 | 
			
		||||
            .sanitize_c = false,
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        llvm.addLibraryPath(.{ .cwd_relative = llvm_lib_dir });
 | 
			
		||||
@ -324,6 +325,7 @@ pub fn build(b: *std.Build) !void {
 | 
			
		||||
        .target = target,
 | 
			
		||||
        .optimize = optimize,
 | 
			
		||||
        .link_libc = true,
 | 
			
		||||
        .sanitize_c = false,
 | 
			
		||||
    });
 | 
			
		||||
    const configuration = b.addOptions();
 | 
			
		||||
    configuration.addOptionPath("c_abi_object_path", c_abi.getEmittedBin());
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										57
									
								
								src/LLVM.zig
									
									
									
									
									
								
							
							
						
						
									
										57
									
								
								src/LLVM.zig
									
									
									
									
									
								
							@ -26,6 +26,24 @@ pub const String = extern struct {
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
pub const Intrinsic = enum {
 | 
			
		||||
    pub const Id = enum(c_uint) {
 | 
			
		||||
        _,
 | 
			
		||||
    };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
pub const Attribute = opaque {
 | 
			
		||||
    pub const Index = enum(c_uint) {
 | 
			
		||||
        @"return" = 0,
 | 
			
		||||
        function = 0xffff_ffff,
 | 
			
		||||
        _,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    pub const Kind = enum(c_uint) {
 | 
			
		||||
        _,
 | 
			
		||||
    };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
pub const CodeModel = enum(u8) {
 | 
			
		||||
    none = 0,
 | 
			
		||||
    tiny = 1,
 | 
			
		||||
@ -488,12 +506,6 @@ const targets = [@typeInfo(Architecture).@"enum".fields.len]type{
 | 
			
		||||
    api.get_initializer(.X86),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
pub const Intrinsic = enum {
 | 
			
		||||
    pub const Id = enum(c_uint) {
 | 
			
		||||
        _,
 | 
			
		||||
    };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
pub const Context = opaque {
 | 
			
		||||
    pub const create = api.LLVMContextCreate;
 | 
			
		||||
 | 
			
		||||
@ -528,6 +540,13 @@ pub const Context = opaque {
 | 
			
		||||
    pub fn get_intrinsic_type(context: *Context, intrinsic_id: Intrinsic.Id, parameter_types: []const *Type) *Type.Function {
 | 
			
		||||
        return api.LLVMIntrinsicGetType(context, intrinsic_id, parameter_types.ptr, parameter_types.len);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn create_string_attribute(context: *Context, attribute_name: []const u8, attribute_value: []const u8) *Attribute {
 | 
			
		||||
        return api.LLVMCreateStringAttribute(context, attribute_name.ptr, @intCast(attribute_name.len), attribute_value.ptr, @intCast(attribute_value.len));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub const create_enum_attribute = api.LLVMCreateEnumAttribute;
 | 
			
		||||
    pub const create_type_attribute = api.LLVMCreateTypeAttribute;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
pub const BasicBlock = opaque {
 | 
			
		||||
@ -741,6 +760,8 @@ pub const Function = opaque {
 | 
			
		||||
    pub const get_calling_convention = api.LLVMGetFunctionCallConv;
 | 
			
		||||
 | 
			
		||||
    pub const get_arguments = api.LLVMGetParams;
 | 
			
		||||
 | 
			
		||||
    pub const add_attribute = api.LLVMAddAttributeAtIndex;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
pub const Constant = opaque {
 | 
			
		||||
@ -771,6 +792,8 @@ pub const Value = opaque {
 | 
			
		||||
    pub const get_type = api.LLVMTypeOf;
 | 
			
		||||
    pub const get_kind = api.LLVMGetValueKind;
 | 
			
		||||
 | 
			
		||||
    pub const is_call_instruction = api.LLVMIsACallInst;
 | 
			
		||||
 | 
			
		||||
    pub fn is_constant(value: *Value) bool {
 | 
			
		||||
        return api.LLVMIsConstant(value) != 0;
 | 
			
		||||
    }
 | 
			
		||||
@ -794,8 +817,8 @@ pub const Value = opaque {
 | 
			
		||||
        const kind = value.get_kind();
 | 
			
		||||
        switch (kind) {
 | 
			
		||||
            .Instruction => {
 | 
			
		||||
                const instruction = value.to_instruction();
 | 
			
		||||
                return instruction.get_calling_convention();
 | 
			
		||||
                const call = value.to_instruction().to_call();
 | 
			
		||||
                return call.get_calling_convention();
 | 
			
		||||
            },
 | 
			
		||||
            .Function => {
 | 
			
		||||
                const function = value.to_function();
 | 
			
		||||
@ -842,8 +865,18 @@ pub const Value = opaque {
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
pub const Instruction = opaque {
 | 
			
		||||
    pub const set_calling_convention = api.LLVMSetInstructionCallConv;
 | 
			
		||||
    pub const get_calling_convention = api.LLVMGetInstructionCallConv;
 | 
			
		||||
    pub fn to_value(instruction: *Instruction) *Value {
 | 
			
		||||
        return @ptrCast(instruction);
 | 
			
		||||
    }
 | 
			
		||||
    pub fn to_call(instruction: *Instruction) *Instruction.Call {
 | 
			
		||||
        assert(instruction.to_value().is_call_instruction() != null);
 | 
			
		||||
        return @ptrCast(instruction);
 | 
			
		||||
    }
 | 
			
		||||
    pub const Call = opaque {
 | 
			
		||||
        pub const set_calling_convention = api.LLVMSetInstructionCallConv;
 | 
			
		||||
        pub const get_calling_convention = api.LLVMGetInstructionCallConv;
 | 
			
		||||
        pub const add_attribute = api.LLVMAddCallSiteAttribute;
 | 
			
		||||
    };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
pub const DI = struct {
 | 
			
		||||
@ -1236,6 +1269,10 @@ pub fn lookup_intrinsic_id(name: []const u8) Intrinsic.Id {
 | 
			
		||||
    return api.LLVMLookupIntrinsicID(name.ptr, name.len);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn lookup_attribute_kind(name: []const u8) Attribute.Kind {
 | 
			
		||||
    return api.LLVMGetEnumAttributeKindForName(name.ptr, name.len);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub const IntPredicate = enum(c_int) {
 | 
			
		||||
    eq = 32,
 | 
			
		||||
    ne,
 | 
			
		||||
 | 
			
		||||
@ -115,9 +115,34 @@ const Module = struct {
 | 
			
		||||
        global_scope: *llvm.DI.Scope,
 | 
			
		||||
        file: *llvm.DI.File,
 | 
			
		||||
        pointer_type: *llvm.Type,
 | 
			
		||||
        // intrinsics: struct {
 | 
			
		||||
        //     trap:
 | 
			
		||||
        // },
 | 
			
		||||
        intrinsic_table: IntrinsicTable,
 | 
			
		||||
        attribute_table: AttributeTable,
 | 
			
		||||
        attribute_kind_table: AttributeKindTable,
 | 
			
		||||
 | 
			
		||||
        const IntrinsicTable = struct {
 | 
			
		||||
            trap: llvm.Intrinsic.Id,
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        const AttributeTable = struct {
 | 
			
		||||
            frame_pointer_all: *llvm.Attribute,
 | 
			
		||||
            ssp: *llvm.Attribute,
 | 
			
		||||
            @"stack-protector-buffer-size": *llvm.Attribute,
 | 
			
		||||
            @"no-trapping-math": *llvm.Attribute,
 | 
			
		||||
            alwaysinline: *llvm.Attribute,
 | 
			
		||||
            @"noinline": *llvm.Attribute,
 | 
			
		||||
            noreturn: *llvm.Attribute,
 | 
			
		||||
            nounwind: *llvm.Attribute,
 | 
			
		||||
            naked: *llvm.Attribute,
 | 
			
		||||
            signext: *llvm.Attribute,
 | 
			
		||||
            zeroext: *llvm.Attribute,
 | 
			
		||||
            inreg: *llvm.Attribute,
 | 
			
		||||
            @"noalias": *llvm.Attribute,
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        const AttributeKindTable = struct {
 | 
			
		||||
            byval: llvm.Attribute.Kind,
 | 
			
		||||
            sret: llvm.Attribute.Kind,
 | 
			
		||||
        };
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    pub fn get_infer_or_ignore_value(module: *Module) *Value {
 | 
			
		||||
@ -179,6 +204,28 @@ const Module = struct {
 | 
			
		||||
                .context = context,
 | 
			
		||||
                .builder = context.create_builder(),
 | 
			
		||||
                .pointer_type = context.get_pointer_type(default_address_space).to_type(),
 | 
			
		||||
                .intrinsic_table = .{
 | 
			
		||||
                    .trap = llvm.lookup_intrinsic_id("llvm.trap"),
 | 
			
		||||
                },
 | 
			
		||||
                .attribute_table = .{
 | 
			
		||||
                    .frame_pointer_all = context.create_string_attribute("frame-pointer", "all"),
 | 
			
		||||
                    .ssp = context.create_enum_attribute(llvm.lookup_attribute_kind("ssp"), 0),
 | 
			
		||||
                    .@"stack-protector-buffer-size" = context.create_string_attribute("stack-protector-buffer-size", "8"),
 | 
			
		||||
                    .@"no-trapping-math" = context.create_string_attribute("no-trapping-math", "true"),
 | 
			
		||||
                    .@"noinline" = context.create_enum_attribute(llvm.lookup_attribute_kind("noinline"), 0),
 | 
			
		||||
                    .alwaysinline = context.create_enum_attribute(llvm.lookup_attribute_kind("alwaysinline"), 0),
 | 
			
		||||
                    .noreturn = context.create_enum_attribute(llvm.lookup_attribute_kind("noreturn"), 0),
 | 
			
		||||
                    .nounwind = context.create_enum_attribute(llvm.lookup_attribute_kind("nounwind"), 0),
 | 
			
		||||
                    .naked = context.create_enum_attribute(llvm.lookup_attribute_kind("naked"), 0),
 | 
			
		||||
                    .signext = context.create_enum_attribute(llvm.lookup_attribute_kind("signext"), 0),
 | 
			
		||||
                    .zeroext = context.create_enum_attribute(llvm.lookup_attribute_kind("zeroext"), 0),
 | 
			
		||||
                    .inreg = context.create_enum_attribute(llvm.lookup_attribute_kind("inreg"), 0),
 | 
			
		||||
                    .@"noalias" = context.create_enum_attribute(llvm.lookup_attribute_kind("noalias"), 0),
 | 
			
		||||
                },
 | 
			
		||||
                .attribute_kind_table = .{
 | 
			
		||||
                    .byval = llvm.lookup_attribute_kind("byval"),
 | 
			
		||||
                    .sret = llvm.lookup_attribute_kind("sret"),
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
@ -302,11 +349,52 @@ const Module = struct {
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const AttributeContainerType = enum {
 | 
			
		||||
    call,
 | 
			
		||||
    function,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
fn llvm_add_function_attribute(value: *llvm.Value, attribute: *llvm.Attribute, container_type: AttributeContainerType) void {
 | 
			
		||||
    switch (container_type) {
 | 
			
		||||
        .call => {
 | 
			
		||||
            const call = value.is_call_instruction() orelse unreachable;
 | 
			
		||||
            call.add_attribute(.function, attribute);
 | 
			
		||||
        },
 | 
			
		||||
        .function => {
 | 
			
		||||
            const function = value.to_function();
 | 
			
		||||
            function.add_attribute(.function, attribute);
 | 
			
		||||
        },
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn llvm_add_argument_attribute(value: *llvm.Value, attribute: *llvm.Attribute, index: c_uint, container_type: AttributeContainerType) void {
 | 
			
		||||
    switch (container_type) {
 | 
			
		||||
        .call => {
 | 
			
		||||
            const call = value.is_call_instruction() orelse unreachable;
 | 
			
		||||
            call.add_attribute(@enumFromInt(index), attribute);
 | 
			
		||||
        },
 | 
			
		||||
        .function => {
 | 
			
		||||
            const function = value.to_function();
 | 
			
		||||
            function.add_attribute(@enumFromInt(index), attribute);
 | 
			
		||||
        },
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub const Function = struct {
 | 
			
		||||
    current_basic_block: *llvm.BasicBlock,
 | 
			
		||||
    current_scope: *llvm.DI.Scope,
 | 
			
		||||
    attributes: Attributes,
 | 
			
		||||
    locals: Variable.Array = .{},
 | 
			
		||||
    arguments: Variable.Array = .{},
 | 
			
		||||
 | 
			
		||||
    const Attributes = struct {
 | 
			
		||||
        inline_behavior: enum {
 | 
			
		||||
            default,
 | 
			
		||||
            always_inline,
 | 
			
		||||
            no_inline,
 | 
			
		||||
        } = .default,
 | 
			
		||||
        naked: bool = false,
 | 
			
		||||
    };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
pub const ConstantInteger = struct {
 | 
			
		||||
@ -363,6 +451,7 @@ const FunctionType = struct {
 | 
			
		||||
    semantic_argument_types: [*]const *Type,
 | 
			
		||||
    argument_type_abis: [*]const Abi.Information,
 | 
			
		||||
    abi_argument_types: [*]const *Type,
 | 
			
		||||
    abi_return_type: *Type,
 | 
			
		||||
    semantic_argument_count: u32,
 | 
			
		||||
    abi_argument_count: u32,
 | 
			
		||||
    calling_convention: CallingConvention,
 | 
			
		||||
@ -787,19 +876,71 @@ const Converter = struct {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn emit_direct_coerce(module: *Module, ty: *Type, original_value: *Value) *llvm.Value {
 | 
			
		||||
        const source_type = original_value.type;
 | 
			
		||||
        const alloca = module.llvm.builder.create_alloca(source_type.llvm.handle, "");
 | 
			
		||||
        _ = module.llvm.builder.create_store(original_value.llvm, alloca);
 | 
			
		||||
 | 
			
		||||
        const target_type = ty;
 | 
			
		||||
        const target_size = ty.get_byte_size();
 | 
			
		||||
        const target_alignment = ty.get_byte_alignment();
 | 
			
		||||
        const source_size = source_type.get_byte_size();
 | 
			
		||||
        const source_alignment = source_type.get_byte_alignment();
 | 
			
		||||
        const target_is_scalable_vector_type = false;
 | 
			
		||||
        const source_is_scalable_vector_type = false;
 | 
			
		||||
        if (source_size >= target_size and !source_is_scalable_vector_type and !target_is_scalable_vector_type) {
 | 
			
		||||
            _ = source_alignment;
 | 
			
		||||
            _ = target_alignment;
 | 
			
		||||
            return module.llvm.builder.create_load(target_type.llvm.handle, alloca);
 | 
			
		||||
        } else {
 | 
			
		||||
            @trap();
 | 
			
		||||
            // const alignment = @max(target_alignment, source_alignment);
 | 
			
		||||
            // const temporal = emit_local_symbol(analyzer, thread, .{
 | 
			
		||||
            //     .name = 0,
 | 
			
		||||
            //     .initial_value = null,
 | 
			
		||||
            //     .type = args.coerced_type,
 | 
			
		||||
            //     .line = 0,
 | 
			
		||||
            //     .column = 0,
 | 
			
		||||
            // });
 | 
			
		||||
            // emit_memcpy(analyzer, thread, .{
 | 
			
		||||
            //     .destination = &temporal.instruction.value,
 | 
			
		||||
            //     .source = &local.instruction.value,
 | 
			
		||||
            //     .destination_alignment = .{
 | 
			
		||||
            //         .alignment = alignment,
 | 
			
		||||
            //     },
 | 
			
		||||
            //     .source_alignment = .{
 | 
			
		||||
            //         .alignment = source_alignment,
 | 
			
		||||
            //     },
 | 
			
		||||
            //     .size = source_size,
 | 
			
		||||
            //     .line = 0,
 | 
			
		||||
            //     .column = 0,
 | 
			
		||||
            //     .scope = analyzer.current_scope,
 | 
			
		||||
            // });
 | 
			
		||||
            //
 | 
			
		||||
            // const load = emit_load(analyzer, thread, .{
 | 
			
		||||
            //     .value = &temporal.instruction.value,
 | 
			
		||||
            //     .type = args.coerced_type,
 | 
			
		||||
            //     .line = 0,
 | 
			
		||||
            //     .column = 0,
 | 
			
		||||
            //     .scope = analyzer.current_scope,
 | 
			
		||||
            // });
 | 
			
		||||
            // return &load.instruction.value;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn parse_call(noalias converter: *Converter, noalias module: *Module, callable: *Value) *Value {
 | 
			
		||||
        var llvm_abi_argument_value_buffer: [64]*llvm.Value = undefined;
 | 
			
		||||
        const function_type = callable.type;
 | 
			
		||||
        const calling_convention = function_type.bb.function.calling_convention;
 | 
			
		||||
        const function_type = &callable.type.bb.function;
 | 
			
		||||
        const calling_convention = function_type.calling_convention;
 | 
			
		||||
        _ = calling_convention;
 | 
			
		||||
        const llvm_indirect_return_value: ?*Value = switch (function_type.bb.function.return_type_abi.kind) {
 | 
			
		||||
        const llvm_indirect_return_value: ?*Value = switch (function_type.return_type_abi.kind) {
 | 
			
		||||
            .indirect => @trap(),
 | 
			
		||||
            else => null,
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        var semantic_argument_count: usize = 0;
 | 
			
		||||
        var abi_argument_count: usize = 0;
 | 
			
		||||
        const function_semantic_argument_count = function_type.bb.function.semantic_argument_count;
 | 
			
		||||
        const function_semantic_argument_count = function_type.semantic_argument_count;
 | 
			
		||||
 | 
			
		||||
        while (true) : (semantic_argument_count += 1) {
 | 
			
		||||
            converter.skip_space();
 | 
			
		||||
@ -813,36 +954,87 @@ const Converter = struct {
 | 
			
		||||
                converter.report_error();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            const semantic_argument_value = converter.parse_value(module, function_type.bb.function.semantic_argument_types[semantic_argument_index], .value);
 | 
			
		||||
            const semantic_argument_value = converter.parse_value(module, function_type.semantic_argument_types[semantic_argument_index], .value);
 | 
			
		||||
 | 
			
		||||
            const argument_abi = function_type.bb.function.argument_type_abis[semantic_argument_index];
 | 
			
		||||
            const argument_abi = function_type.argument_type_abis[semantic_argument_index];
 | 
			
		||||
 | 
			
		||||
            switch (argument_abi.kind) {
 | 
			
		||||
                .direct => {
 | 
			
		||||
                    llvm_abi_argument_value_buffer[abi_argument_count] = semantic_argument_value.llvm;
 | 
			
		||||
                    abi_argument_count += 1;
 | 
			
		||||
                },
 | 
			
		||||
                else => @trap(),
 | 
			
		||||
                .ignore => unreachable,
 | 
			
		||||
                .direct_pair => unreachable,
 | 
			
		||||
                .direct_coerce => |coerced_type| {
 | 
			
		||||
                    const v = emit_direct_coerce(module, coerced_type, semantic_argument_value);
 | 
			
		||||
                    llvm_abi_argument_value_buffer[abi_argument_count] = v;
 | 
			
		||||
                    abi_argument_count += 1;
 | 
			
		||||
                },
 | 
			
		||||
                .direct_coerce_int => unreachable,
 | 
			
		||||
                .expand_coerce => unreachable,
 | 
			
		||||
                .direct_split_struct_i32 => unreachable,
 | 
			
		||||
                .indirect => unreachable,
 | 
			
		||||
                .expand => unreachable,
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        assert(abi_argument_count == function_type.bb.function.abi_argument_count);
 | 
			
		||||
        assert(abi_argument_count == function_type.abi_argument_count);
 | 
			
		||||
 | 
			
		||||
        const llvm_abi_argument_values = llvm_abi_argument_value_buffer[0..abi_argument_count];
 | 
			
		||||
        const llvm_call = module.llvm.builder.create_call(callable.type.llvm.handle.to_function(), callable.llvm, llvm_abi_argument_values);
 | 
			
		||||
        llvm_call.to_instruction().set_calling_convention(callable.llvm.get_calling_convention());
 | 
			
		||||
 | 
			
		||||
        llvm_call.to_instruction().to_call().set_calling_convention(callable.llvm.get_calling_convention());
 | 
			
		||||
 | 
			
		||||
        llvm_emit_function_attributes(module, llvm_call, function_type, Function.Attributes{}, .call);
 | 
			
		||||
 | 
			
		||||
        for (function_type.get_argument_type_abis()) |argument_type_abi| {
 | 
			
		||||
            if (argument_type_abi.attributes.zero_extend) {
 | 
			
		||||
                llvm_add_argument_attribute(llvm_call, module.llvm.attribute_table.zeroext, argument_type_abi.indices[0], .call);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (argument_type_abi.attributes.sign_extend) {
 | 
			
		||||
                llvm_add_argument_attribute(llvm_call, module.llvm.attribute_table.signext, argument_type_abi.indices[0], .call);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            switch (argument_type_abi.kind) {
 | 
			
		||||
                .indirect => |indirect| {
 | 
			
		||||
                    if (argument_type_abi.attributes.by_value) {
 | 
			
		||||
                        const by_value_attribute = module.llvm.context.create_type_attribute(module.llvm.attribute_kind_table.byval, indirect.type.llvm.handle);
 | 
			
		||||
                        llvm_add_argument_attribute(llvm_call, by_value_attribute, argument_type_abi.indices[0], .call);
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    // TODO: alignment
 | 
			
		||||
                },
 | 
			
		||||
                else => {},
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        var llvm_value = llvm_call;
 | 
			
		||||
        var return_type = function_type.abi_return_type;
 | 
			
		||||
        _ = &return_type;
 | 
			
		||||
        _ = &llvm_value;
 | 
			
		||||
 | 
			
		||||
        switch (function_type.return_type_abi.kind) {
 | 
			
		||||
            .expand, .direct_split_struct_i32 => unreachable,
 | 
			
		||||
            .ignore => {},
 | 
			
		||||
            .indirect => {
 | 
			
		||||
                @trap();
 | 
			
		||||
            },
 | 
			
		||||
            .direct => {},
 | 
			
		||||
            else => @trap(),
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (llvm_indirect_return_value) |indirect_value| {
 | 
			
		||||
            _ = indirect_value;
 | 
			
		||||
            @trap();
 | 
			
		||||
        } else {
 | 
			
		||||
            const call = module.values.add();
 | 
			
		||||
            call.* = .{
 | 
			
		||||
                .llvm = llvm_call,
 | 
			
		||||
                .type = function_type.bb.function.semantic_return_type,
 | 
			
		||||
            const result = module.values.add();
 | 
			
		||||
            result.* = .{
 | 
			
		||||
                .llvm = llvm_value,
 | 
			
		||||
                .type = return_type,
 | 
			
		||||
                .bb = .instruction,
 | 
			
		||||
            };
 | 
			
		||||
            return call;
 | 
			
		||||
            return result;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -1334,11 +1526,11 @@ const Converter = struct {
 | 
			
		||||
 | 
			
		||||
                // TODO: lookup in advance
 | 
			
		||||
                const intrinsic_id = llvm.lookup_intrinsic_id("llvm.trap");
 | 
			
		||||
                const parameter_types: []const *llvm.Type = &.{};
 | 
			
		||||
                const parameter_values: []const *llvm.Value = &.{};
 | 
			
		||||
                const intrinsic_function = module.llvm.handle.get_intrinsic_declaration(intrinsic_id, parameter_types);
 | 
			
		||||
                const intrinsic_function_type = module.llvm.context.get_intrinsic_type(intrinsic_id, parameter_types);
 | 
			
		||||
                const llvm_call = module.llvm.builder.create_call(intrinsic_function_type, intrinsic_function, parameter_values);
 | 
			
		||||
                const argument_types: []const *llvm.Type = &.{};
 | 
			
		||||
                const argument_values: []const *llvm.Value = &.{};
 | 
			
		||||
                const intrinsic_function = module.llvm.handle.get_intrinsic_declaration(intrinsic_id, argument_types);
 | 
			
		||||
                const intrinsic_function_type = module.llvm.context.get_intrinsic_type(intrinsic_id, argument_types);
 | 
			
		||||
                const llvm_call = module.llvm.builder.create_call(intrinsic_function_type, intrinsic_function, argument_values);
 | 
			
		||||
                _ = module.llvm.builder.create_unreachable();
 | 
			
		||||
 | 
			
		||||
                const value = module.values.add();
 | 
			
		||||
@ -2189,6 +2381,89 @@ const ConvertOptions = struct {
 | 
			
		||||
    target: Target,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
fn llvm_emit_function_attributes(module: *Module, value: *llvm.Value, function_type: *FunctionType, function_attributes: Function.Attributes, container_type: AttributeContainerType) void {
 | 
			
		||||
    const enable_frame_pointer = true;
 | 
			
		||||
 | 
			
		||||
    if (enable_frame_pointer) {
 | 
			
		||||
        llvm_add_function_attribute(value, module.llvm.attribute_table.frame_pointer_all, container_type);
 | 
			
		||||
        llvm_add_function_attribute(value, module.llvm.attribute_table.ssp, container_type);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    llvm_add_function_attribute(value, module.llvm.attribute_table.@"stack-protector-buffer-size", container_type);
 | 
			
		||||
    llvm_add_function_attribute(value, module.llvm.attribute_table.@"no-trapping-math", container_type);
 | 
			
		||||
    llvm_add_function_attribute(value, module.llvm.attribute_table.nounwind, container_type);
 | 
			
		||||
 | 
			
		||||
    switch (function_attributes.inline_behavior) {
 | 
			
		||||
        .default => {},
 | 
			
		||||
        .no_inline => llvm_add_function_attribute(value, module.llvm.attribute_table.@"noinline", container_type),
 | 
			
		||||
        .always_inline => llvm_add_function_attribute(value, module.llvm.attribute_table.alwaysinline, container_type),
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (function_attributes.naked) {
 | 
			
		||||
        llvm_add_function_attribute(value, module.llvm.attribute_table.naked, container_type);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (function_type.abi_return_type == module.noreturn_type) {
 | 
			
		||||
        llvm_add_function_attribute(value, module.llvm.attribute_table.noreturn, container_type);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn llvm_emit_function_site_argument_attributes(noalias module: *Module, function: *llvm.Value, argument_abi: Abi.Information, is_return: bool) void {
 | 
			
		||||
 | 
			
		||||
    // assert(argument_abi.indices[1] == argument_abi.indices[0] or argument_abi.kind == .direct_pair or argument_abi.kind == .direct or argument_abi.kind == .ignore or argument_abi.kind == .expand or argument_abi.kind == .direct_coerce or argument_abi.kind == .direct_coerce_int or argument_abi.kind == .expand_coerce or argument_abi.kind == .direct_split_struct_i32);
 | 
			
		||||
 | 
			
		||||
    if (argument_abi.attributes.zero_extend) {
 | 
			
		||||
        llvm_add_argument_attribute(function, module.llvm.attribute_table.zeroext, argument_abi.indices[0], .function);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (argument_abi.attributes.sign_extend) {
 | 
			
		||||
        llvm_add_argument_attribute(function, module.llvm.attribute_table.signext, argument_abi.indices[0], .function);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (argument_abi.attributes.by_reg) {
 | 
			
		||||
        llvm_add_argument_attribute(function, module.llvm.attribute_table.inreg, argument_abi.indices[0], .function);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    switch (argument_abi.kind) {
 | 
			
		||||
        .direct => {},
 | 
			
		||||
        .indirect => |indirect| switch (is_return) {
 | 
			
		||||
            true => {
 | 
			
		||||
                const sret_attribute = module.llvm.context.create_type_attribute(module.llvm.attribute_kind_table.sret, indirect.type.llvm.handle);
 | 
			
		||||
                llvm_add_argument_attribute(function, sret_attribute, argument_abi.indices[0], .function);
 | 
			
		||||
                llvm_add_argument_attribute(function, module.llvm.attribute_table.@"noalias", argument_abi.indices[0], .function);
 | 
			
		||||
 | 
			
		||||
                // TODO: alignment
 | 
			
		||||
            },
 | 
			
		||||
            false => {
 | 
			
		||||
                if (argument_abi.attributes.by_value) {
 | 
			
		||||
                    const by_value_attribute = module.llvm.context.create_type_attribute(module.llvm.attribute_kind_table.byval, indirect.type.llvm.handle);
 | 
			
		||||
                    llvm_add_argument_attribute(function, by_value_attribute, argument_abi.indices[0], .function);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // TODO: alignment
 | 
			
		||||
            },
 | 
			
		||||
        },
 | 
			
		||||
        else => {},
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn llvm_emit_function_site_attributes(module: *Module, value: *Value) void {
 | 
			
		||||
    const llvm_value = value.llvm;
 | 
			
		||||
    const function_type = &value.type.bb.function;
 | 
			
		||||
    const function_attributes = switch (value.bb) {
 | 
			
		||||
        .function => value.bb.function.attributes,
 | 
			
		||||
        else => Function.Attributes{},
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    llvm_emit_function_attributes(module, llvm_value, function_type, function_attributes, .function);
 | 
			
		||||
 | 
			
		||||
    llvm_emit_function_site_argument_attributes(module, llvm_value, function_type.return_type_abi, true);
 | 
			
		||||
 | 
			
		||||
    for (function_type.get_argument_type_abis()) |argument_type_abi| {
 | 
			
		||||
        llvm_emit_function_site_argument_attributes(module, llvm_value, argument_type_abi, false);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub noinline fn convert(options: ConvertOptions) void {
 | 
			
		||||
    var converter = Converter{
 | 
			
		||||
        .content = options.content,
 | 
			
		||||
@ -2266,6 +2541,8 @@ pub noinline fn convert(options: ConvertOptions) void {
 | 
			
		||||
                switch (global_kind) {
 | 
			
		||||
                    .@"fn" => {
 | 
			
		||||
                        var calling_convention = CallingConvention.unknown;
 | 
			
		||||
                        var function_attributes = Function.Attributes{};
 | 
			
		||||
                        _ = &function_attributes;
 | 
			
		||||
 | 
			
		||||
                        if (converter.consume_character_if_match(left_bracket)) {
 | 
			
		||||
                            while (converter.offset < converter.content.len) {
 | 
			
		||||
@ -2478,8 +2755,6 @@ pub noinline fn convert(options: ConvertOptions) void {
 | 
			
		||||
                                                    assert(type_classes[1] != .memory or type_classes[0] == .memory);
 | 
			
		||||
                                                    assert(type_classes[1] != .sseup or type_classes[0] == .sse);
 | 
			
		||||
 | 
			
		||||
                                                    _ = &needed_registers; // autofix
 | 
			
		||||
 | 
			
		||||
                                                    const result_type = switch (type_classes[0]) {
 | 
			
		||||
                                                        .integer => b: {
 | 
			
		||||
                                                            needed_registers.gpr += 1;
 | 
			
		||||
@ -2493,7 +2768,7 @@ pub noinline fn convert(options: ConvertOptions) void {
 | 
			
		||||
 | 
			
		||||
                                                                break :ata .{
 | 
			
		||||
                                                                    .kind = .{
 | 
			
		||||
                                                                        .direct_coerce = semantic_argument_type,
 | 
			
		||||
                                                                        .direct_coerce = result_type,
 | 
			
		||||
                                                                    },
 | 
			
		||||
                                                                    .attributes = .{
 | 
			
		||||
                                                                        .sign_extend = signed,
 | 
			
		||||
@ -2501,6 +2776,7 @@ pub noinline fn convert(options: ConvertOptions) void {
 | 
			
		||||
                                                                    },
 | 
			
		||||
                                                                };
 | 
			
		||||
                                                            }
 | 
			
		||||
 | 
			
		||||
                                                            break :b result_type;
 | 
			
		||||
                                                        },
 | 
			
		||||
                                                        .memory => break :ata Abi.SystemV.indirect_argument(semantic_argument_type, available_registers.gpr),
 | 
			
		||||
@ -2670,9 +2946,7 @@ pub noinline fn convert(options: ConvertOptions) void {
 | 
			
		||||
                            },
 | 
			
		||||
                            .type = llvm_function_type,
 | 
			
		||||
                        });
 | 
			
		||||
                        llvm_handle.set_calling_convention(calling_convention.to_llvm());
 | 
			
		||||
 | 
			
		||||
                        const global = module.globals.add();
 | 
			
		||||
                        var subroutine_type: *llvm.DI.Type.Subroutine = undefined;
 | 
			
		||||
                        const current_scope: *llvm.DI.Scope = if (module.llvm.di_builder) |di_builder| blk: {
 | 
			
		||||
                            const subroutine_type_flags = llvm.DI.Flags{};
 | 
			
		||||
@ -2708,49 +2982,49 @@ pub noinline fn convert(options: ConvertOptions) void {
 | 
			
		||||
                                    .semantic_argument_count = semantic_argument_count,
 | 
			
		||||
                                    .abi_argument_count = @intCast(abi_argument_type_count),
 | 
			
		||||
                                    .abi_argument_types = abi_argument_types.ptr,
 | 
			
		||||
                                    .abi_return_type = abi_return_type,
 | 
			
		||||
                                    .argument_type_abis = argument_type_abis.ptr,
 | 
			
		||||
                                    .return_type_abi = return_type_abi,
 | 
			
		||||
                                },
 | 
			
		||||
                            },
 | 
			
		||||
                        });
 | 
			
		||||
 | 
			
		||||
                        if (converter.consume_character_if_match(';')) {
 | 
			
		||||
                            const value = module.values.add();
 | 
			
		||||
                            value.* = .{
 | 
			
		||||
                                .llvm = llvm_handle.to_value(),
 | 
			
		||||
                                .type = function_type,
 | 
			
		||||
                                .bb = .external_function,
 | 
			
		||||
                            };
 | 
			
		||||
                        llvm_handle.set_calling_convention(calling_convention.to_llvm());
 | 
			
		||||
                        const has_semicolon = converter.consume_character_if_match(';');
 | 
			
		||||
 | 
			
		||||
                            global.* = .{
 | 
			
		||||
                                .value = value,
 | 
			
		||||
                                .name = global_name,
 | 
			
		||||
                            };
 | 
			
		||||
                        } else {
 | 
			
		||||
                            const entry_block = module.llvm.context.create_basic_block("entry", llvm_handle);
 | 
			
		||||
                            module.llvm.builder.position_at_end(entry_block);
 | 
			
		||||
                        const value = module.values.add();
 | 
			
		||||
                        value.* = .{
 | 
			
		||||
                            .llvm = llvm_handle.to_value(),
 | 
			
		||||
                            .type = function_type,
 | 
			
		||||
                            .bb = switch (has_semicolon) {
 | 
			
		||||
                                true => .external_function,
 | 
			
		||||
                                false => .{
 | 
			
		||||
                                    .function = .{
 | 
			
		||||
                                        .current_basic_block = blk: {
 | 
			
		||||
                                            const entry_block = module.llvm.context.create_basic_block("entry", llvm_handle);
 | 
			
		||||
                                            module.llvm.builder.position_at_end(entry_block);
 | 
			
		||||
                                            break :blk entry_block;
 | 
			
		||||
                                        },
 | 
			
		||||
                                        .current_scope = current_scope,
 | 
			
		||||
                                        .attributes = function_attributes,
 | 
			
		||||
                                    },
 | 
			
		||||
                                },
 | 
			
		||||
                            },
 | 
			
		||||
                        };
 | 
			
		||||
 | 
			
		||||
                        const global = module.globals.add();
 | 
			
		||||
                        global.* = .{
 | 
			
		||||
                            .value = value,
 | 
			
		||||
                            .name = global_name,
 | 
			
		||||
                        };
 | 
			
		||||
 | 
			
		||||
                        llvm_emit_function_site_attributes(module, value);
 | 
			
		||||
 | 
			
		||||
                        if (!has_semicolon) {
 | 
			
		||||
                            var llvm_argument_buffer: [argument_buffer.len]*llvm.Argument = undefined;
 | 
			
		||||
                            llvm_handle.get_arguments(&llvm_argument_buffer);
 | 
			
		||||
                            const llvm_arguments = llvm_argument_buffer[0..semantic_argument_count];
 | 
			
		||||
 | 
			
		||||
                            const value = module.values.add();
 | 
			
		||||
                            value.* = .{
 | 
			
		||||
                                .llvm = llvm_handle.to_value(),
 | 
			
		||||
                                .type = function_type,
 | 
			
		||||
                                .bb = .{
 | 
			
		||||
                                    .function = .{
 | 
			
		||||
                                        .current_basic_block = entry_block,
 | 
			
		||||
                                        .current_scope = current_scope,
 | 
			
		||||
                                    },
 | 
			
		||||
                                },
 | 
			
		||||
                            };
 | 
			
		||||
 | 
			
		||||
                            global.* = .{
 | 
			
		||||
                                .value = value,
 | 
			
		||||
                                .name = global_name,
 | 
			
		||||
                            };
 | 
			
		||||
 | 
			
		||||
                            module.current_function = global;
 | 
			
		||||
                            defer module.current_function = null;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -7,6 +7,8 @@ pub extern fn llvm_context_create_module(context: *llvm.Context, name: llvm.Stri
 | 
			
		||||
pub extern fn LLVMContextCreate() *llvm.Context;
 | 
			
		||||
pub extern fn LLVMCreateBuilderInContext(context: *llvm.Context) *llvm.Builder;
 | 
			
		||||
 | 
			
		||||
pub extern fn LLVMIsACallInst(value: *llvm.Value) ?*llvm.Instruction.Call;
 | 
			
		||||
 | 
			
		||||
// Module
 | 
			
		||||
pub extern fn llvm_module_create_global_variable(module: *llvm.Module, global_type: *llvm.Type, is_constant: bool, linkage: llvm.LinkageType, initial_value: *llvm.Constant, name: llvm.String, before: ?*llvm.GlobalVariable, thread_local_mode: llvm.ThreadLocalMode, address_space: c_uint, externally_initialized: bool) *llvm.GlobalVariable;
 | 
			
		||||
pub extern fn llvm_module_create_function(module: *llvm.Module, function_type: *llvm.Type.Function, linkage_type: llvm.LinkageType, address_space: c_uint, name: llvm.String) *llvm.Function;
 | 
			
		||||
@ -17,8 +19,8 @@ pub extern fn LLVMGetBasicBlockTerminator(basic_block: *llvm.BasicBlock) ?*llvm.
 | 
			
		||||
pub extern fn LLVMSetFunctionCallConv(function: *llvm.Function, calling_convention: llvm.CallingConvention) void;
 | 
			
		||||
pub extern fn LLVMGetFunctionCallConv(function: *llvm.Function) llvm.CallingConvention;
 | 
			
		||||
 | 
			
		||||
pub extern fn LLVMSetInstructionCallConv(instruction: *llvm.Instruction, calling_convention: llvm.CallingConvention) void;
 | 
			
		||||
pub extern fn LLVMGetInstructionCallConv(instruction: *llvm.Instruction) llvm.CallingConvention;
 | 
			
		||||
pub extern fn LLVMSetInstructionCallConv(instruction: *llvm.Instruction.Call, calling_convention: llvm.CallingConvention) void;
 | 
			
		||||
pub extern fn LLVMGetInstructionCallConv(instruction: *llvm.Instruction.Call) llvm.CallingConvention;
 | 
			
		||||
 | 
			
		||||
pub extern fn LLVMGetParams(function: *llvm.Function, argument_buffer: [*]*llvm.Argument) void;
 | 
			
		||||
 | 
			
		||||
@ -70,6 +72,17 @@ pub extern fn LLVMLookupIntrinsicID(name_pointer: [*]const u8, name_length: usiz
 | 
			
		||||
pub extern fn LLVMGetIntrinsicDeclaration(module: *llvm.Module, intrinsic_id: llvm.Intrinsic.Id, parameter_type_pointer: [*]const *llvm.Type, parameter_type_count: usize) *llvm.Value;
 | 
			
		||||
pub extern fn LLVMIntrinsicGetType(context: *llvm.Context, intrinsic_id: llvm.Intrinsic.Id, parameter_type_pointer: [*]const *llvm.Type, parameter_type_count: usize) *llvm.Type.Function;
 | 
			
		||||
 | 
			
		||||
// Attributes
 | 
			
		||||
pub extern fn LLVMGetEnumAttributeKindForName(name_pointer: [*]const u8, name_length: usize) llvm.Attribute.Kind;
 | 
			
		||||
 | 
			
		||||
pub extern fn LLVMCreateEnumAttribute(context: *llvm.Context, kind: llvm.Attribute.Kind, value: u64) *llvm.Attribute;
 | 
			
		||||
pub extern fn LLVMCreateTypeAttribute(context: *llvm.Context, kind: llvm.Attribute.Kind, ty: *llvm.Type) *llvm.Attribute;
 | 
			
		||||
pub extern fn LLVMCreateConstantRangeAttribute(context: *llvm.Context, kind: llvm.Attribute.Kind, bit_count: c_uint, lower_words: [*]const u64, upper_words: [*]const u64) *llvm.Attribute;
 | 
			
		||||
pub extern fn LLVMCreateStringAttribute(context: *llvm.Context, key_pointer: [*]const u8, key_length: c_uint, value_pointer: [*]const u8, value_length: usize) *llvm.Attribute;
 | 
			
		||||
 | 
			
		||||
pub extern fn LLVMAddAttributeAtIndex(function: *llvm.Function, attribute_index: llvm.Attribute.Index, attribute: *llvm.Attribute) void;
 | 
			
		||||
pub extern fn LLVMAddCallSiteAttribute(call: *llvm.Instruction.Call, attribute_index: llvm.Attribute.Index, attribute: *llvm.Attribute) void;
 | 
			
		||||
 | 
			
		||||
// TYPES
 | 
			
		||||
// Types: integers
 | 
			
		||||
pub extern fn LLVMVoidTypeInContext(context: *llvm.Context) *llvm.Type;
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user