diff --git a/src/llvm_abi.cpp b/src/llvm_abi.cpp index c2298bcd0..d8f16b451 100644 --- a/src/llvm_abi.cpp +++ b/src/llvm_abi.cpp @@ -10,21 +10,35 @@ struct lbArgType { LLVMTypeRef cast_type; // Optional LLVMTypeRef pad_type; // Optional LLVMAttributeRef attribute; // Optional + LLVMAttributeRef align_attribute; // Optional }; + +i64 lb_sizeof(LLVMTypeRef type); +i64 lb_alignof(LLVMTypeRef type); + lbArgType lb_arg_type_direct(LLVMTypeRef type, LLVMTypeRef cast_type, LLVMTypeRef pad_type, LLVMAttributeRef attr) { - return lbArgType{lbArg_Direct, type, cast_type, pad_type, attr}; + return lbArgType{lbArg_Direct, type, cast_type, pad_type, attr, nullptr}; } lbArgType lb_arg_type_direct(LLVMTypeRef type) { return lb_arg_type_direct(type, nullptr, nullptr, nullptr); } lbArgType lb_arg_type_indirect(LLVMTypeRef type, LLVMAttributeRef attr) { - return lbArgType{lbArg_Indirect, type, nullptr, nullptr, attr}; + return lbArgType{lbArg_Indirect, type, nullptr, nullptr, attr, nullptr}; +} + +lbArgType lb_arg_type_indirect_byval(LLVMContextRef c, LLVMTypeRef type) { + i64 alignment = lb_alignof(type); + alignment = gb_max(alignment, 8); + + LLVMAttributeRef byval_attr = lb_create_enum_attribute_with_type(c, "byval", type); + LLVMAttributeRef align_attr = lb_create_enum_attribute(c, "align", alignment); + return lbArgType{lbArg_Indirect, type, nullptr, nullptr, byval_attr, align_attr}; } lbArgType lb_arg_type_ignore(LLVMTypeRef type) { - return lbArgType{lbArg_Ignore, type, nullptr, nullptr, nullptr}; + return lbArgType{lbArg_Ignore, type, nullptr, nullptr, nullptr, nullptr}; } struct lbFunctionType { @@ -121,6 +135,9 @@ void lb_add_function_type_attributes(LLVMValueRef fn, lbFunctionType *ft, ProcCa if (arg->attribute) { LLVMAddAttributeAtIndex(fn, arg_index+1, arg->attribute); } + if (arg->align_attribute) { + LLVMAddAttributeAtIndex(fn, arg_index+1, arg->align_attribute); + } arg_index++; } @@ -145,8 +162,6 @@ void lb_add_function_type_attributes(LLVMValueRef fn, lbFunctionType *ft, ProcCa } -i64 lb_sizeof(LLVMTypeRef type); -i64 lb_alignof(LLVMTypeRef type); i64 lb_sizeof(LLVMTypeRef type) { LLVMTypeKind kind = LLVMGetTypeKind(type); @@ -328,7 +343,7 @@ namespace lbAbi386 { if (sz == 0) { args[i] = lb_arg_type_ignore(t); } else { - args[i] = lb_arg_type_indirect(t, lb_create_enum_attribute(c, "byval")); + args[i] = lb_arg_type_indirect_byval(c, t); } } else { args[i] = non_struct(c, t, false); @@ -348,7 +363,7 @@ namespace lbAbi386 { case 4: return lb_arg_type_direct(return_type, LLVMIntTypeInContext(c, 32), nullptr, nullptr); case 8: return lb_arg_type_direct(return_type, LLVMIntTypeInContext(c, 64), nullptr, nullptr); } - LLVMAttributeRef attr = lb_create_enum_attribute(c, "sret"); + LLVMAttributeRef attr = lb_create_enum_attribute_with_type(c, "sret", return_type); return lb_arg_type_indirect(return_type, attr); } return non_struct(c, return_type, true); @@ -512,9 +527,9 @@ namespace lbAbiAmd64SysV { if (is_mem_cls(cls, attribute_kind)) { LLVMAttributeRef attribute = nullptr; if (attribute_kind == Amd64TypeAttribute_ByVal) { - attribute = lb_create_enum_attribute(c, "byval"); + return lb_arg_type_indirect_byval(c, type); } else if (attribute_kind == Amd64TypeAttribute_StructRect) { - attribute = lb_create_enum_attribute(c, "sret"); + attribute = lb_create_enum_attribute_with_type(c, "sret", type); } return lb_arg_type_indirect(type, attribute); } else { @@ -814,7 +829,7 @@ namespace lbAbiAmd64SysV { if (sz == 0) { args[i] = lb_arg_type_ignore(t); } else { - args[i] = lb_arg_type_indirect(t, lb_create_enum_attribute(c, "byval")); + args[i] = lb_arg_type_indirect(t, lb_create_enum_attribute_with_type(c, "byval", t)); } } else { args[i] = non_struct(c, t); @@ -834,7 +849,7 @@ namespace lbAbiAmd64SysV { case 4: return lb_arg_type_direct(return_type, LLVMIntTypeInContext(c, 32), nullptr, nullptr); case 8: return lb_arg_type_direct(return_type, LLVMIntTypeInContext(c, 64), nullptr, nullptr); } - LLVMAttributeRef attr = lb_create_enum_attribute(c, "sret"); + LLVMAttributeRef attr = lb_create_enum_attribute_with_type(c, "sret", return_type); return lb_arg_type_indirect(return_type, attr); } else if (build_context.metrics.os == TargetOs_windows && lb_is_type_kind(return_type, LLVMIntegerTypeKind) && lb_sizeof(return_type) == 16) { return lb_arg_type_direct(return_type, LLVMIntTypeInContext(c, 128), nullptr, nullptr); @@ -984,7 +999,7 @@ namespace lbAbiArm64 { } return lb_arg_type_direct(type, cast_type, nullptr, nullptr); } else { - LLVMAttributeRef attr = lb_create_enum_attribute(c, "sret"); + LLVMAttributeRef attr = lb_create_enum_attribute_with_type(c, "sret", type); return lb_arg_type_indirect(type, attr); } } diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index d92df5ae2..28c37be7d 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -2545,6 +2545,27 @@ lbValue lb_emit_string(lbProcedure *p, lbValue str_elem, lbValue str_len) { } } +LLVMAttributeRef lb_create_enum_attribute_with_type(LLVMContextRef ctx, char const *name, LLVMTypeRef type) { + String s = make_string_c(name); + + // NOTE(2021-02-25, bill); All this attributes require a type associated with them + // and the current LLVM C API does not expose this functionality yet. + // It is better to ignore the attributes for the time being + if (s == "byval") { + // return nullptr; + } else if (s == "byref") { + return nullptr; + } else if (s == "preallocated") { + return nullptr; + } else if (s == "sret") { + // return nullptr; + } + + unsigned kind = LLVMGetEnumAttributeKindForName(name, s.len); + GB_ASSERT_MSG(kind != 0, "unknown attribute: %s", name); + return LLVMCreateEnumAttribute(ctx, kind, 0); +} + LLVMAttributeRef lb_create_enum_attribute(LLVMContextRef ctx, char const *name, u64 value) { String s = make_string_c(name); @@ -2552,13 +2573,13 @@ LLVMAttributeRef lb_create_enum_attribute(LLVMContextRef ctx, char const *name, // and the current LLVM C API does not expose this functionality yet. // It is better to ignore the attributes for the time being if (s == "byval") { - return nullptr; + GB_PANIC("lb_create_enum_attribute_with_type should be used for %s", name); } else if (s == "byref") { - return nullptr; + GB_PANIC("lb_create_enum_attribute_with_type should be used for %s", name); } else if (s == "preallocated") { - return nullptr; + GB_PANIC("lb_create_enum_attribute_with_type should be used for %s", name); } else if (s == "sret") { - return nullptr; + GB_PANIC("lb_create_enum_attribute_with_type should be used for %s", name); } unsigned kind = LLVMGetEnumAttributeKindForName(name, s.len); diff --git a/src/llvm_backend.hpp b/src/llvm_backend.hpp index f212d9fc0..b35c042ee 100644 --- a/src/llvm_backend.hpp +++ b/src/llvm_backend.hpp @@ -276,6 +276,7 @@ String lb_mangle_name(lbModule *m, Entity *e); String lb_get_entity_name(lbModule *m, Entity *e, String name = {}); LLVMAttributeRef lb_create_enum_attribute(LLVMContextRef ctx, char const *name, u64 value=0); +LLVMAttributeRef lb_create_enum_attribute_with_type(LLVMContextRef ctx, char const *name, LLVMTypeRef type); void lb_add_proc_attribute_at_index(lbProcedure *p, isize index, char const *name, u64 value); void lb_add_proc_attribute_at_index(lbProcedure *p, isize index, char const *name); lbProcedure *lb_create_procedure(lbModule *module, Entity *entity, bool ignore_body=false);