1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321 |
- enum lbArgKind {
- lbArg_Direct,
- lbArg_Indirect,
- lbArg_Ignore,
- };
- struct lbArgType {
- lbArgKind kind;
- LLVMTypeRef type;
- LLVMTypeRef cast_type; // Optional
- LLVMTypeRef pad_type; // Optional
- LLVMAttributeRef attribute; // Optional
- LLVMAttributeRef align_attribute; // Optional
- i64 byval_alignment;
- bool is_byval;
- };
- 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, nullptr, 0, false};
- }
- 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, nullptr, 0, false};
- }
- 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, alignment, true};
- }
- lbArgType lb_arg_type_ignore(LLVMTypeRef type) {
- return lbArgType{lbArg_Ignore, type, nullptr, nullptr, nullptr, nullptr, 0, false};
- }
- struct lbFunctionType {
- LLVMContextRef ctx;
- ProcCallingConvention calling_convention;
- Array<lbArgType> args;
- lbArgType ret;
- };
- i64 llvm_align_formula(i64 off, i64 a) {
- return (off + a - 1) / a * a;
- }
- bool lb_is_type_kind(LLVMTypeRef type, LLVMTypeKind kind) {
- if (type == nullptr) {
- return false;
- }
- return LLVMGetTypeKind(type) == kind;
- }
- LLVMTypeRef lb_function_type_to_llvm_ptr(lbFunctionType *ft, bool is_var_arg) {
- unsigned arg_count = cast(unsigned)ft->args.count;
- unsigned offset = 0;
- LLVMTypeRef ret = nullptr;
- if (ft->ret.kind == lbArg_Direct) {
- if (ft->ret.cast_type != nullptr) {
- ret = ft->ret.cast_type;
- } else {
- ret = ft->ret.type;
- }
- } else if (ft->ret.kind == lbArg_Indirect) {
- offset += 1;
- ret = LLVMVoidTypeInContext(ft->ctx);
- } else if (ft->ret.kind == lbArg_Ignore) {
- ret = LLVMVoidTypeInContext(ft->ctx);
- }
- GB_ASSERT_MSG(ret != nullptr, "%d", ft->ret.kind);
- unsigned maximum_arg_count = offset+arg_count;
- LLVMTypeRef *args = gb_alloc_array(permanent_allocator(), LLVMTypeRef, maximum_arg_count);
- if (offset == 1) {
- GB_ASSERT(ft->ret.kind == lbArg_Indirect);
- args[0] = LLVMPointerType(ft->ret.type, 0);
- }
- unsigned arg_index = offset;
- for (unsigned i = 0; i < arg_count; i++) {
- lbArgType *arg = &ft->args[i];
- if (arg->kind == lbArg_Direct) {
- LLVMTypeRef arg_type = nullptr;
- if (ft->args[i].cast_type != nullptr) {
- arg_type = arg->cast_type;
- } else {
- arg_type = arg->type;
- }
- args[arg_index++] = arg_type;
- } else if (arg->kind == lbArg_Indirect) {
- GB_ASSERT(!lb_is_type_kind(arg->type, LLVMPointerTypeKind));
- args[arg_index++] = LLVMPointerType(arg->type, 0);
- } else if (arg->kind == lbArg_Ignore) {
- // ignore
- }
- }
- unsigned total_arg_count = arg_index;
- LLVMTypeRef func_type = LLVMFunctionType(ret, args, total_arg_count, is_var_arg);
- return LLVMPointerType(func_type, 0);
- }
- void lb_add_function_type_attributes(LLVMValueRef fn, lbFunctionType *ft, ProcCallingConvention calling_convention) {
- if (ft == nullptr) {
- return;
- }
- unsigned arg_count = cast(unsigned)ft->args.count;
- unsigned offset = 0;
- if (ft->ret.kind == lbArg_Indirect) {
- offset += 1;
- }
- LLVMContextRef c = ft->ctx;
- LLVMAttributeRef noalias_attr = lb_create_enum_attribute(c, "noalias");
- LLVMAttributeRef nonnull_attr = lb_create_enum_attribute(c, "nonnull");
- LLVMAttributeRef nocapture_attr = lb_create_enum_attribute(c, "nocapture");
- unsigned arg_index = offset;
- for (unsigned i = 0; i < arg_count; i++) {
- lbArgType *arg = &ft->args[i];
- if (arg->kind == lbArg_Ignore) {
- continue;
- }
- if (arg->attribute) {
- LLVMAddAttributeAtIndex(fn, arg_index+1, arg->attribute);
- }
- if (arg->align_attribute) {
- LLVMAddAttributeAtIndex(fn, arg_index+1, arg->align_attribute);
- }
- arg_index++;
- }
- if (offset != 0 && ft->ret.kind == lbArg_Indirect && ft->ret.attribute != nullptr) {
- LLVMAddAttributeAtIndex(fn, offset, ft->ret.attribute);
- LLVMAddAttributeAtIndex(fn, offset, noalias_attr);
- }
- lbCallingConventionKind cc_kind = lbCallingConvention_C;
- // TODO(bill): Clean up this logic
- if (!is_arch_wasm()) {
- cc_kind = lb_calling_convention_map[calling_convention];
- }
- // if (build_context.metrics.arch == TargetArch_amd64) {
- // if (build_context.metrics.os == TargetOs_windows) {
- // if (cc_kind == lbCallingConvention_C) {
- // cc_kind = lbCallingConvention_Win64;
- // }
- // } else {
- // if (cc_kind == lbCallingConvention_C) {
- // cc_kind = lbCallingConvention_X86_64_SysV;
- // }
- // }
- // }
- LLVMSetFunctionCallConv(fn, cc_kind);
- if (calling_convention == ProcCC_Odin) {
- unsigned context_index = offset+arg_count;
- LLVMAddAttributeAtIndex(fn, context_index, noalias_attr);
- LLVMAddAttributeAtIndex(fn, context_index, nonnull_attr);
- LLVMAddAttributeAtIndex(fn, context_index, nocapture_attr);
- }
- }
- i64 lb_sizeof(LLVMTypeRef type) {
- LLVMTypeKind kind = LLVMGetTypeKind(type);
- switch (kind) {
- case LLVMVoidTypeKind:
- return 0;
- case LLVMIntegerTypeKind:
- {
- unsigned w = LLVMGetIntTypeWidth(type);
- return (w + 7)/8;
- }
- case LLVMHalfTypeKind:
- return 2;
- case LLVMFloatTypeKind:
- return 4;
- case LLVMDoubleTypeKind:
- return 8;
- case LLVMPointerTypeKind:
- return build_context.word_size;
- case LLVMStructTypeKind:
- {
- unsigned field_count = LLVMCountStructElementTypes(type);
- i64 offset = 0;
- if (LLVMIsPackedStruct(type)) {
- for (unsigned i = 0; i < field_count; i++) {
- LLVMTypeRef field = LLVMStructGetTypeAtIndex(type, i);
- offset += lb_sizeof(field);
- }
- } else {
- for (unsigned i = 0; i < field_count; i++) {
- LLVMTypeRef field = LLVMStructGetTypeAtIndex(type, i);
- i64 align = lb_alignof(field);
- offset = llvm_align_formula(offset, align);
- offset += lb_sizeof(field);
- }
- offset = llvm_align_formula(offset, lb_alignof(type));
- }
- return offset;
- }
- break;
- case LLVMArrayTypeKind:
- {
- LLVMTypeRef elem = LLVMGetElementType(type);
- i64 elem_size = lb_sizeof(elem);
- i64 count = LLVMGetArrayLength(type);
- i64 size = count * elem_size;
- return size;
- }
- break;
- case LLVMX86_MMXTypeKind:
- return 8;
- case LLVMVectorTypeKind:
- {
- LLVMTypeRef elem = LLVMGetElementType(type);
- i64 elem_size = lb_sizeof(elem);
- i64 count = LLVMGetVectorSize(type);
- i64 size = count * elem_size;
- return gb_clamp(next_pow2(size), 1, build_context.max_align);
- }
- }
- GB_PANIC("Unhandled type for lb_sizeof -> %s", LLVMPrintTypeToString(type));
- return 0;
- }
- i64 lb_alignof(LLVMTypeRef type) {
- LLVMTypeKind kind = LLVMGetTypeKind(type);
- switch (kind) {
- case LLVMVoidTypeKind:
- return 1;
- case LLVMIntegerTypeKind:
- {
- unsigned w = LLVMGetIntTypeWidth(type);
- return gb_clamp((w + 7)/8, 1, build_context.word_size);
- }
- case LLVMHalfTypeKind:
- return 2;
- case LLVMFloatTypeKind:
- return 4;
- case LLVMDoubleTypeKind:
- return 8;
- case LLVMPointerTypeKind:
- return build_context.word_size;
- case LLVMStructTypeKind:
- {
- if (LLVMIsPackedStruct(type)) {
- return 1;
- } else {
- unsigned field_count = LLVMCountStructElementTypes(type);
- i64 max_align = 1;
- for (unsigned i = 0; i < field_count; i++) {
- LLVMTypeRef field = LLVMStructGetTypeAtIndex(type, i);
- i64 field_align = lb_alignof(field);
- max_align = gb_max(max_align, field_align);
- }
- return max_align;
- }
- }
- break;
- case LLVMArrayTypeKind:
- return lb_alignof(LLVMGetElementType(type));
- case LLVMX86_MMXTypeKind:
- return 8;
- case LLVMVectorTypeKind:
- {
- // TODO(bill): This appears to be correct but LLVM isn't necessarily "great" with regards to documentation
- LLVMTypeRef elem = LLVMGetElementType(type);
- i64 elem_size = lb_sizeof(elem);
- i64 count = LLVMGetVectorSize(type);
- i64 size = count * elem_size;
- return gb_clamp(next_pow2(size), 1, build_context.max_align);
- }
- }
- GB_PANIC("Unhandled type for lb_sizeof -> %s", LLVMPrintTypeToString(type));
- // LLVMValueRef v = LLVMAlignOf(type);
- // GB_ASSERT(LLVMIsConstant(v));
- // return LLVMConstIntGetSExtValue(v);
- return 1;
- }
- #define LB_ABI_INFO(name) lbFunctionType *name(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count, LLVMTypeRef return_type, bool return_is_defined, ProcCallingConvention calling_convention)
- typedef LB_ABI_INFO(lbAbiInfoType);
- // NOTE(bill): I hate `namespace` in C++ but this is just because I don't want to prefix everything
- namespace lbAbi386 {
- Array<lbArgType> compute_arg_types(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count);
- lbArgType compute_return_type(LLVMContextRef c, LLVMTypeRef return_type, bool return_is_defined);
- LB_ABI_INFO(abi_info) {
- lbFunctionType *ft = gb_alloc_item(permanent_allocator(), lbFunctionType);
- ft->ctx = c;
- ft->args = compute_arg_types(c, arg_types, arg_count);
- ft->ret = compute_return_type(c, return_type, return_is_defined);
- ft->calling_convention = calling_convention;
- return ft;
- }
- lbArgType non_struct(LLVMContextRef c, LLVMTypeRef type, bool is_return) {
- if (!is_return && lb_sizeof(type) > 8) {
- return lb_arg_type_indirect(type, nullptr);
- }
- if (build_context.metrics.os == TargetOs_windows &&
- build_context.word_size == 8 &&
- lb_is_type_kind(type, LLVMIntegerTypeKind) &&
- type == LLVMIntTypeInContext(c, 128)) {
- // NOTE(bill): Because Windows AMD64 is weird
- // TODO(bill): LLVM is probably bugged here and doesn't correctly generate the right code
- // So even though it is "technically" wrong, no cast might be the best option
- LLVMTypeRef cast_type = nullptr;
- if (true || !is_return) {
- cast_type = LLVMVectorType(LLVMInt64TypeInContext(c), 2);
- }
- return lb_arg_type_direct(type, cast_type, nullptr, nullptr);
- }
- LLVMAttributeRef attr = nullptr;
- LLVMTypeRef i1 = LLVMInt1TypeInContext(c);
- if (type == i1) {
- attr = lb_create_enum_attribute(c, "zeroext");
- }
- return lb_arg_type_direct(type, nullptr, nullptr, attr);
- }
- Array<lbArgType> compute_arg_types(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count) {
- auto args = array_make<lbArgType>(heap_allocator(), arg_count);
- for (unsigned i = 0; i < arg_count; i++) {
- LLVMTypeRef t = arg_types[i];
- LLVMTypeKind kind = LLVMGetTypeKind(t);
- i64 sz = lb_sizeof(t);
- if (kind == LLVMStructTypeKind || kind == LLVMArrayTypeKind) {
- if (sz == 0) {
- args[i] = lb_arg_type_ignore(t);
- } else {
- args[i] = lb_arg_type_indirect(t, nullptr);
- }
- } else {
- args[i] = non_struct(c, t, false);
- }
- }
- return args;
- }
- lbArgType compute_return_type(LLVMContextRef c, LLVMTypeRef return_type, bool return_is_defined) {
- if (!return_is_defined) {
- return lb_arg_type_direct(LLVMVoidTypeInContext(c));
- } else if (lb_is_type_kind(return_type, LLVMStructTypeKind) || lb_is_type_kind(return_type, LLVMArrayTypeKind)) {
- i64 sz = lb_sizeof(return_type);
- switch (sz) {
- case 1: return lb_arg_type_direct(return_type, LLVMIntTypeInContext(c, 8), nullptr, nullptr);
- case 2: return lb_arg_type_direct(return_type, LLVMIntTypeInContext(c, 16), nullptr, nullptr);
- 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_with_type(c, "sret", return_type);
- return lb_arg_type_indirect(return_type, attr);
- }
- return non_struct(c, return_type, true);
- }
- };
- namespace lbAbiAmd64Win64 {
- Array<lbArgType> compute_arg_types(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count);
- LB_ABI_INFO(abi_info) {
- lbFunctionType *ft = gb_alloc_item(permanent_allocator(), lbFunctionType);
- ft->ctx = c;
- ft->args = compute_arg_types(c, arg_types, arg_count);
- ft->ret = lbAbi386::compute_return_type(c, return_type, return_is_defined);
- ft->calling_convention = calling_convention;
- return ft;
- }
- Array<lbArgType> compute_arg_types(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count) {
- auto args = array_make<lbArgType>(heap_allocator(), arg_count);
- for (unsigned i = 0; i < arg_count; i++) {
- LLVMTypeRef t = arg_types[i];
- LLVMTypeKind kind = LLVMGetTypeKind(t);
- if (kind == LLVMStructTypeKind || kind == LLVMArrayTypeKind) {
- i64 sz = lb_sizeof(t);
- switch (sz) {
- case 1:
- case 2:
- case 4:
- case 8:
- args[i] = lb_arg_type_direct(t, LLVMIntTypeInContext(c, 8*cast(unsigned)sz), nullptr, nullptr);
- break;
- default:
- args[i] = lb_arg_type_indirect(t, nullptr);
- break;
- }
- } else {
- args[i] = lbAbi386::non_struct(c, t, false);
- }
- }
- return args;
- }
- };
- // NOTE(bill): I hate `namespace` in C++ but this is just because I don't want to prefix everything
- namespace lbAbiAmd64SysV {
- enum RegClass {
- RegClass_NoClass,
- RegClass_Int,
- RegClass_SSEFs,
- RegClass_SSEFv,
- RegClass_SSEDs,
- RegClass_SSEDv,
- RegClass_SSEInt8,
- RegClass_SSEInt16,
- RegClass_SSEInt32,
- RegClass_SSEInt64,
- RegClass_SSEUp,
- RegClass_X87,
- RegClass_X87Up,
- RegClass_ComplexX87,
- RegClass_Memory,
- };
- bool is_sse(RegClass reg_class) {
- switch (reg_class) {
- case RegClass_SSEFs:
- case RegClass_SSEFv:
- case RegClass_SSEDs:
- case RegClass_SSEDv:
- return true;
- case RegClass_SSEInt8:
- case RegClass_SSEInt16:
- case RegClass_SSEInt32:
- case RegClass_SSEInt64:
- return true;
- }
- return false;
- }
- void all_mem(Array<RegClass> *cs) {
- for_array(i, *cs) {
- (*cs)[i] = RegClass_Memory;
- }
- }
- enum Amd64TypeAttributeKind {
- Amd64TypeAttribute_None,
- Amd64TypeAttribute_ByVal,
- Amd64TypeAttribute_StructRect,
- };
- lbArgType compute_return_type(LLVMContextRef c, LLVMTypeRef return_type, bool return_is_defined);
- void classify_with(LLVMTypeRef t, Array<RegClass> *cls, i64 ix, i64 off);
- void fixup(LLVMTypeRef t, Array<RegClass> *cls);
- lbArgType amd64_type(LLVMContextRef c, LLVMTypeRef type, Amd64TypeAttributeKind attribute_kind, ProcCallingConvention calling_convention);
- Array<RegClass> classify(LLVMTypeRef t);
- LLVMTypeRef llreg(LLVMContextRef c, Array<RegClass> const ®_classes);
- LB_ABI_INFO(abi_info) {
- lbFunctionType *ft = gb_alloc_item(permanent_allocator(), lbFunctionType);
- ft->ctx = c;
- ft->calling_convention = calling_convention;
- ft->args = array_make<lbArgType>(heap_allocator(), arg_count);
- for (unsigned i = 0; i < arg_count; i++) {
- ft->args[i] = amd64_type(c, arg_types[i], Amd64TypeAttribute_ByVal, calling_convention);
- }
- if (return_is_defined) {
- ft->ret = amd64_type(c, return_type, Amd64TypeAttribute_StructRect, calling_convention);
- } else {
- ft->ret = lb_arg_type_direct(LLVMVoidTypeInContext(c));
- }
- return ft;
- }
- bool is_mem_cls(Array<RegClass> const &cls, Amd64TypeAttributeKind attribute_kind) {
- if (attribute_kind == Amd64TypeAttribute_ByVal) {
- if (cls.count == 0) {
- return false;
- }
- auto first = cls[0];
- return first == RegClass_Memory || first == RegClass_X87 || first == RegClass_ComplexX87;
- } else if (attribute_kind == Amd64TypeAttribute_StructRect) {
- if (cls.count == 0) {
- return false;
- }
- return cls[0] == RegClass_Memory;
- }
- return false;
- }
- bool is_register(LLVMTypeRef type) {
- LLVMTypeKind kind = LLVMGetTypeKind(type);
- i64 sz = lb_sizeof(type);
- if (sz == 0) {
- return false;
- }
- switch (kind) {
- case LLVMIntegerTypeKind:
- case LLVMHalfTypeKind:
- case LLVMFloatTypeKind:
- case LLVMDoubleTypeKind:
- case LLVMPointerTypeKind:
- return true;
- }
- return false;
- }
- lbArgType amd64_type(LLVMContextRef c, LLVMTypeRef type, Amd64TypeAttributeKind attribute_kind, ProcCallingConvention calling_convention) {
- if (is_register(type)) {
- LLVMAttributeRef attribute = nullptr;
- if (type == LLVMInt1TypeInContext(c)) {
- attribute = lb_create_enum_attribute(c, "zeroext");
- }
- return lb_arg_type_direct(type, nullptr, nullptr, attribute);
- }
- auto cls = classify(type);
- if (is_mem_cls(cls, attribute_kind)) {
- LLVMAttributeRef attribute = nullptr;
- if (attribute_kind == Amd64TypeAttribute_ByVal) {
- if (!is_calling_convention_odin(calling_convention)) {
- return lb_arg_type_indirect_byval(c, type);
- }
- attribute = nullptr;
- } else if (attribute_kind == Amd64TypeAttribute_StructRect) {
- attribute = lb_create_enum_attribute_with_type(c, "sret", type);
- }
- return lb_arg_type_indirect(type, attribute);
- } else {
- return lb_arg_type_direct(type, llreg(c, cls), nullptr, nullptr);
- }
- }
- lbArgType non_struct(LLVMContextRef c, LLVMTypeRef type) {
- LLVMAttributeRef attr = nullptr;
- LLVMTypeRef i1 = LLVMInt1TypeInContext(c);
- if (type == i1) {
- attr = lb_create_enum_attribute(c, "zeroext");
- }
- return lb_arg_type_direct(type, nullptr, nullptr, attr);
- }
- Array<RegClass> classify(LLVMTypeRef t) {
- i64 sz = lb_sizeof(t);
- i64 words = (sz + 7)/8;
- auto reg_classes = array_make<RegClass>(heap_allocator(), cast(isize)words);
- if (words > 4) {
- all_mem(®_classes);
- } else {
- classify_with(t, ®_classes, 0, 0);
- fixup(t, ®_classes);
- }
- return reg_classes;
- }
- void unify(Array<RegClass> *cls, i64 i, RegClass const newv) {
- RegClass const oldv = (*cls)[cast(isize)i];
- if (oldv == newv) {
- return;
- }
- RegClass to_write = newv;
- if (oldv == RegClass_NoClass) {
- to_write = newv;
- } else if (newv == RegClass_NoClass) {
- return;
- } else if (oldv == RegClass_Memory || newv == RegClass_Memory) {
- to_write = RegClass_Memory;
- } else if (oldv == RegClass_Int || newv == RegClass_Int) {
- to_write = RegClass_Int;
- } else if (oldv == RegClass_X87 || oldv == RegClass_X87Up || oldv == RegClass_ComplexX87) {
- to_write = RegClass_Memory;
- } else if (newv == RegClass_X87 || newv == RegClass_X87Up || newv == RegClass_ComplexX87) {
- to_write = RegClass_Memory;
- } else if (newv == RegClass_SSEUp) {
- switch (oldv) {
- case RegClass_SSEFv:
- case RegClass_SSEFs:
- case RegClass_SSEDv:
- case RegClass_SSEDs:
- case RegClass_SSEInt8:
- case RegClass_SSEInt16:
- case RegClass_SSEInt32:
- case RegClass_SSEInt64:
- return;
- }
- }
- (*cls)[cast(isize)i] = to_write;
- }
- void fixup(LLVMTypeRef t, Array<RegClass> *cls) {
- i64 i = 0;
- i64 e = cls->count;
- if (e > 2 && (lb_is_type_kind(t, LLVMStructTypeKind) ||
- lb_is_type_kind(t, LLVMArrayTypeKind) ||
- lb_is_type_kind(t, LLVMVectorTypeKind))) {
- RegClass &oldv = (*cls)[cast(isize)i];
- if (is_sse(oldv)) {
- for (i++; i < e; i++) {
- if (oldv != RegClass_SSEUp) {
- all_mem(cls);
- return;
- }
- }
- } else {
- all_mem(cls);
- return;
- }
- } else {
- while (i < e) {
- RegClass &oldv = (*cls)[cast(isize)i];
- if (oldv == RegClass_Memory) {
- all_mem(cls);
- return;
- } else if (oldv == RegClass_X87Up) {
- // NOTE(bill): Darwin
- all_mem(cls);
- return;
- } else if (oldv == RegClass_SSEUp) {
- oldv = RegClass_SSEDv;
- } else if (is_sse(oldv)) {
- i++;
- while (i != e && oldv == RegClass_SSEUp) {
- i++;
- }
- } else if (oldv == RegClass_X87) {
- i++;
- while (i != e && oldv == RegClass_X87Up) {
- i++;
- }
- } else {
- i++;
- }
- }
- }
- }
- unsigned llvec_len(Array<RegClass> const ®_classes, isize offset) {
- unsigned len = 1;
- for (isize i = offset; i < reg_classes.count; i++) {
- if (reg_classes[i] != RegClass_SSEUp) {
- break;
- }
- len++;
- }
- return len;
- }
- LLVMTypeRef llreg(LLVMContextRef c, Array<RegClass> const ®_classes) {
- auto types = array_make<LLVMTypeRef>(heap_allocator(), 0, reg_classes.count);
- for (isize i = 0; i < reg_classes.count; /**/) {
- RegClass reg_class = reg_classes[i];
- switch (reg_class) {
- case RegClass_Int:
- array_add(&types, LLVMIntTypeInContext(c, 64));
- break;
- case RegClass_SSEFv:
- case RegClass_SSEDv:
- case RegClass_SSEInt8:
- case RegClass_SSEInt16:
- case RegClass_SSEInt32:
- case RegClass_SSEInt64:
- {
- unsigned elems_per_word = 0;
- LLVMTypeRef elem_type = nullptr;
- switch (reg_class) {
- case RegClass_SSEFv:
- elems_per_word = 2;
- elem_type = LLVMFloatTypeInContext(c);
- break;
- case RegClass_SSEDv:
- elems_per_word = 1;
- elem_type = LLVMDoubleTypeInContext(c);
- break;
- case RegClass_SSEInt8:
- elems_per_word = 64/8;
- elem_type = LLVMIntTypeInContext(c, 8);
- break;
- case RegClass_SSEInt16:
- elems_per_word = 64/16;
- elem_type = LLVMIntTypeInContext(c, 16);
- break;
- case RegClass_SSEInt32:
- elems_per_word = 64/32;
- elem_type = LLVMIntTypeInContext(c, 32);
- break;
- case RegClass_SSEInt64:
- elems_per_word = 64/64;
- elem_type = LLVMIntTypeInContext(c, 64);
- break;
- }
- unsigned vec_len = llvec_len(reg_classes, i+1);
- LLVMTypeRef vec_type = LLVMVectorType(elem_type, vec_len * elems_per_word);
- array_add(&types, vec_type);
- i += vec_len;
- continue;
- }
- break;
- case RegClass_SSEFs:
- array_add(&types, LLVMFloatTypeInContext(c));
- break;
- case RegClass_SSEDs:
- array_add(&types, LLVMDoubleTypeInContext(c));
- break;
- default:
- GB_PANIC("Unhandled RegClass");
- }
- i += 1;
- }
- if (types.count == 1) {
- return types[0];
- }
- return LLVMStructTypeInContext(c, types.data, cast(unsigned)types.count, false);
- }
- void classify_with(LLVMTypeRef t, Array<RegClass> *cls, i64 ix, i64 off) {
- i64 t_align = lb_alignof(t);
- i64 t_size = lb_sizeof(t);
- i64 misalign = off % t_align;
- if (misalign != 0) {
- i64 e = (off + t_size + 7) / 8;
- for (i64 i = off / 8; i < e; i++) {
- unify(cls, ix+i, RegClass_Memory);
- }
- return;
- }
- switch (LLVMGetTypeKind(t)) {
- case LLVMIntegerTypeKind:
- case LLVMPointerTypeKind:
- case LLVMHalfTypeKind:
- unify(cls, ix + off/8, RegClass_Int);
- break;
- case LLVMFloatTypeKind:
- unify(cls, ix + off/8, (off%8 == 4) ? RegClass_SSEFv : RegClass_SSEFs);
- break;
- case LLVMDoubleTypeKind:
- unify(cls, ix + off/8, RegClass_SSEDs);
- break;
- case LLVMStructTypeKind:
- {
- LLVMBool packed = LLVMIsPackedStruct(t);
- unsigned field_count = LLVMCountStructElementTypes(t);
- i64 field_off = off;
- for (unsigned field_index = 0; field_index < field_count; field_index++) {
- LLVMTypeRef field_type = LLVMStructGetTypeAtIndex(t, field_index);
- if (!packed) {
- field_off = llvm_align_formula(field_off, lb_alignof(field_type));
- }
- classify_with(field_type, cls, ix, field_off);
- field_off += lb_sizeof(field_type);
- }
- }
- break;
- case LLVMArrayTypeKind:
- {
- i64 len = LLVMGetArrayLength(t);
- LLVMTypeRef elem = LLVMGetElementType(t);
- i64 elem_sz = lb_sizeof(elem);
- for (i64 i = 0; i < len; i++) {
- classify_with(elem, cls, ix, off + i*elem_sz);
- }
- }
- break;
- case LLVMVectorTypeKind:
- {
- i64 len = LLVMGetVectorSize(t);
- LLVMTypeRef elem = LLVMGetElementType(t);
- i64 elem_sz = lb_sizeof(elem);
- LLVMTypeKind elem_kind = LLVMGetTypeKind(elem);
- RegClass reg = RegClass_NoClass;
- switch (elem_kind) {
- case LLVMIntegerTypeKind:
- case LLVMHalfTypeKind:
- switch (LLVMGetIntTypeWidth(elem)) {
- case 8: reg = RegClass_SSEInt8;
- case 16: reg = RegClass_SSEInt16;
- case 32: reg = RegClass_SSEInt32;
- case 64: reg = RegClass_SSEInt64;
- default:
- GB_PANIC("Unhandled integer width for vector type");
- }
- break;
- case LLVMFloatTypeKind:
- reg = RegClass_SSEFv;
- break;
- case LLVMDoubleTypeKind:
- reg = RegClass_SSEDv;
- break;
- default:
- GB_PANIC("Unhandled vector element type");
- }
- for (i64 i = 0; i < len; i++) {
- unify(cls, ix + (off + i*elem_sz)/8, reg);
- // NOTE(bill): Everything after the first one is the upper
- // half of a register
- reg = RegClass_SSEUp;
- }
- }
- break;
- default:
- GB_PANIC("Unhandled type");
- break;
- }
- }
- lbArgType compute_return_type(LLVMContextRef c, LLVMTypeRef return_type, bool return_is_defined) {
- if (!return_is_defined) {
- return lb_arg_type_direct(LLVMVoidTypeInContext(c));
- } else if (lb_is_type_kind(return_type, LLVMStructTypeKind)) {
- i64 sz = lb_sizeof(return_type);
- switch (sz) {
- case 1: return lb_arg_type_direct(return_type, LLVMIntTypeInContext(c, 8), nullptr, nullptr);
- case 2: return lb_arg_type_direct(return_type, LLVMIntTypeInContext(c, 16), nullptr, nullptr);
- 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_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);
- }
- return non_struct(c, return_type);
- }
- };
- namespace lbAbiArm64 {
- Array<lbArgType> compute_arg_types(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count);
- lbArgType compute_return_type(LLVMContextRef c, LLVMTypeRef return_type, bool return_is_defined);
- bool is_homogenous_aggregate(LLVMContextRef c, LLVMTypeRef type, LLVMTypeRef *base_type_, unsigned *member_count_);
- LB_ABI_INFO(abi_info) {
- lbFunctionType *ft = gb_alloc_item(permanent_allocator(), lbFunctionType);
- ft->ctx = c;
- ft->ret = compute_return_type(c, return_type, return_is_defined);
- ft -> args = compute_arg_types(c, arg_types, arg_count);
- ft->calling_convention = calling_convention;
- return ft;
- }
- bool is_register(LLVMTypeRef type) {
- LLVMTypeKind kind = LLVMGetTypeKind(type);
- switch (kind) {
- case LLVMIntegerTypeKind:
- case LLVMHalfTypeKind:
- case LLVMFloatTypeKind:
- case LLVMDoubleTypeKind:
- case LLVMPointerTypeKind:
- return true;
- }
- return false;
- }
- lbArgType non_struct(LLVMContextRef c, LLVMTypeRef type) {
- LLVMAttributeRef attr = nullptr;
- LLVMTypeRef i1 = LLVMInt1TypeInContext(c);
- if (type == i1) {
- attr = lb_create_enum_attribute(c, "zeroext");
- }
- return lb_arg_type_direct(type, nullptr, nullptr, attr);
- }
- bool is_homogenous_array(LLVMContextRef c, LLVMTypeRef type, LLVMTypeRef *base_type_, unsigned *member_count_) {
- GB_ASSERT(lb_is_type_kind(type, LLVMArrayTypeKind));
- unsigned len = LLVMGetArrayLength(type);
- if (len == 0) {
- return false;
- }
- LLVMTypeRef elem = LLVMGetElementType(type);
- LLVMTypeRef base_type = nullptr;
- unsigned member_count = 0;
- if (is_homogenous_aggregate(c, elem, &base_type, &member_count)) {
- if (base_type_) *base_type_ = base_type;
- if (member_count_) *member_count_ = member_count * len;
- return true;
- }
- return false;
- }
- bool is_homogenous_struct(LLVMContextRef c, LLVMTypeRef type, LLVMTypeRef *base_type_, unsigned *member_count_) {
- GB_ASSERT(lb_is_type_kind(type, LLVMStructTypeKind));
- unsigned elem_count = LLVMCountStructElementTypes(type);
- if (elem_count == 0) {
- return false;
- }
- LLVMTypeRef base_type = nullptr;
- unsigned member_count = 0;
- for (unsigned i = 0; i < elem_count; i++) {
- LLVMTypeRef field_type = nullptr;
- unsigned field_member_count = 0;
- LLVMTypeRef elem = LLVMStructGetTypeAtIndex(type, i);
- if (!is_homogenous_aggregate(c, elem, &field_type, &field_member_count)) {
- return false;
- }
- if (base_type == nullptr) {
- base_type = field_type;
- member_count = field_member_count;
- } else {
- if (base_type != field_type) {
- return false;
- }
- member_count += field_member_count;
- }
- }
- if (base_type == nullptr) {
- return false;
- }
- if (lb_sizeof(type) == lb_sizeof(base_type) * member_count) {
- if (base_type_) *base_type_ = base_type;
- if (member_count_) *member_count_ = member_count;
- return true;
- }
- return false;
- }
- bool is_homogenous_aggregate(LLVMContextRef c, LLVMTypeRef type, LLVMTypeRef *base_type_, unsigned *member_count_) {
- LLVMTypeKind kind = LLVMGetTypeKind(type);
- switch (kind) {
- case LLVMFloatTypeKind:
- case LLVMDoubleTypeKind:
- if (base_type_) *base_type_ = type;
- if (member_count_) *member_count_ = 1;
- return true;
- case LLVMArrayTypeKind:
- return is_homogenous_array(c, type, base_type_, member_count_);
- case LLVMStructTypeKind:
- return is_homogenous_struct(c, type, base_type_, member_count_);
- }
- return false;
- }
-
- unsigned is_homogenous_aggregate_small_enough(LLVMTypeRef *base_type_, unsigned member_count_) {
- return (member_count_ <= 4);
- }
- lbArgType compute_return_type(LLVMContextRef c, LLVMTypeRef type, bool return_is_defined) {
- LLVMTypeRef homo_base_type = {};
- unsigned homo_member_count = 0;
- if (!return_is_defined) {
- return lb_arg_type_direct(LLVMVoidTypeInContext(c));
- } else if (is_register(type)) {
- return non_struct(c, type);
- } else if (is_homogenous_aggregate(c, type, &homo_base_type, &homo_member_count)) {
- if(is_homogenous_aggregate_small_enough(&homo_base_type, homo_member_count)) {
- return lb_arg_type_direct(type, LLVMArrayType(homo_base_type, homo_member_count), nullptr, nullptr);
- } else {
- //TODO(Platin): do i need to create stuff that can handle the diffrent return type?
- // else this needs a fix in llvm_backend_proc as we would need to cast it to the correct array type
-
- //LLVMTypeRef array_type = LLVMArrayType(homo_base_type, homo_member_count);
- LLVMAttributeRef attr = lb_create_enum_attribute_with_type(c, "sret", type);
- return lb_arg_type_indirect(type, attr);
- }
- } else {
- i64 size = lb_sizeof(type);
- if (size <= 16) {
- LLVMTypeRef cast_type = nullptr;
- if (size <= 1) {
- cast_type = LLVMInt8TypeInContext(c);
- } else if (size <= 2) {
- cast_type = LLVMInt16TypeInContext(c);
- } else if (size <= 4) {
- cast_type = LLVMInt32TypeInContext(c);
- } else if (size <= 8) {
- cast_type = LLVMInt64TypeInContext(c);
- } else {
- unsigned count = cast(unsigned)((size+7)/8);
- cast_type = LLVMArrayType(LLVMInt64TypeInContext(c), count);
- }
- return lb_arg_type_direct(type, cast_type, nullptr, nullptr);
- } else {
- LLVMAttributeRef attr = lb_create_enum_attribute_with_type(c, "sret", type);
- return lb_arg_type_indirect(type, attr);
- }
- }
- }
-
- Array<lbArgType> compute_arg_types(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count) {
- auto args = array_make<lbArgType>(heap_allocator(), arg_count);
- for (unsigned i = 0; i < arg_count; i++) {
- LLVMTypeRef type = arg_types[i];
- LLVMTypeRef homo_base_type = {};
- unsigned homo_member_count = 0;
- if (is_register(type)) {
- args[i] = non_struct(c, type);
- } else if (is_homogenous_aggregate(c, type, &homo_base_type, &homo_member_count)) {
- args[i] = lb_arg_type_direct(type, LLVMArrayType(homo_base_type, homo_member_count), nullptr, nullptr);
- } else {
- i64 size = lb_sizeof(type);
- if (size <= 16) {
- LLVMTypeRef cast_type = nullptr;
- if (size <= 1) {
- cast_type = LLVMIntTypeInContext(c, 8);
- } else if (size <= 2) {
- cast_type = LLVMIntTypeInContext(c, 16);
- } else if (size <= 4) {
- cast_type = LLVMIntTypeInContext(c, 32);
- } else if (size <= 8) {
- cast_type = LLVMIntTypeInContext(c, 64);
- } else {
- unsigned count = cast(unsigned)((size+7)/8);
- cast_type = LLVMArrayType(LLVMIntTypeInContext(c, 64), count);
- }
- args[i] = lb_arg_type_direct(type, cast_type, nullptr, nullptr);
- } else {
- args[i] = lb_arg_type_indirect(type, nullptr);
- }
- }
- }
- return args;
- }
- }
- namespace lbAbiWasm {
- /*
- NOTE(bill): All of this is custom since there is not an "official"
- ABI definition for WASM, especially for Odin.
- The approach taken optimizes for passing things in multiple
- registers/arguments if possible rather than by pointer.
- */
- Array<lbArgType> compute_arg_types(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count);
- lbArgType compute_return_type(LLVMContextRef c, LLVMTypeRef return_type, bool return_is_defined);
- enum {MAX_DIRECT_STRUCT_SIZE = 32};
- LB_ABI_INFO(abi_info) {
- lbFunctionType *ft = gb_alloc_item(permanent_allocator(), lbFunctionType);
- ft->ctx = c;
- ft->args = compute_arg_types(c, arg_types, arg_count);
- ft->ret = compute_return_type(c, return_type, return_is_defined);
- ft->calling_convention = calling_convention;
- return ft;
- }
- lbArgType non_struct(LLVMContextRef c, LLVMTypeRef type, bool is_return) {
- if (!is_return && type == LLVMIntTypeInContext(c, 128)) {
- LLVMTypeRef cast_type = LLVMVectorType(LLVMInt64TypeInContext(c), 2);
- return lb_arg_type_direct(type, cast_type, nullptr, nullptr);
- }
-
- if (!is_return && lb_sizeof(type) > 8) {
- return lb_arg_type_indirect(type, nullptr);
- }
- LLVMAttributeRef attr = nullptr;
- LLVMTypeRef i1 = LLVMInt1TypeInContext(c);
- if (type == i1) {
- attr = lb_create_enum_attribute(c, "zeroext");
- }
- return lb_arg_type_direct(type, nullptr, nullptr, attr);
- }
-
- bool is_basic_register_type(LLVMTypeRef type) {
- switch (LLVMGetTypeKind(type)) {
- case LLVMHalfTypeKind:
- case LLVMFloatTypeKind:
- case LLVMDoubleTypeKind:
- case LLVMPointerTypeKind:
- return true;
- case LLVMIntegerTypeKind:
- return lb_sizeof(type) <= 8;
- }
- return false;
- }
- bool type_can_be_direct(LLVMTypeRef type) {
- LLVMTypeKind kind = LLVMGetTypeKind(type);
- i64 sz = lb_sizeof(type);
- if (sz == 0) {
- return false;
- }
- if (sz <= MAX_DIRECT_STRUCT_SIZE) {
- if (kind == LLVMArrayTypeKind) {
- if (is_basic_register_type(LLVMGetElementType(type))) {
- return true;
- }
- } else if (kind == LLVMStructTypeKind) {
- unsigned count = LLVMCountStructElementTypes(type);
- for (unsigned i = 0; i < count; i++) {
- LLVMTypeRef elem = LLVMStructGetTypeAtIndex(type, i);
- if (!is_basic_register_type(elem)) {
- return false;
- }
- }
- return true;
- }
- }
- return false;
- }
- lbArgType is_struct(LLVMContextRef c, LLVMTypeRef type) {
- LLVMTypeKind kind = LLVMGetTypeKind(type);
- GB_ASSERT(kind == LLVMArrayTypeKind || kind == LLVMStructTypeKind);
-
- i64 sz = lb_sizeof(type);
- if (sz == 0) {
- return lb_arg_type_ignore(type);
- }
- if (type_can_be_direct(type)) {
- return lb_arg_type_direct(type);
- }
- return lb_arg_type_indirect(type, nullptr);
- }
-
- Array<lbArgType> compute_arg_types(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count) {
- auto args = array_make<lbArgType>(heap_allocator(), arg_count);
- for (unsigned i = 0; i < arg_count; i++) {
- LLVMTypeRef t = arg_types[i];
- LLVMTypeKind kind = LLVMGetTypeKind(t);
- if (kind == LLVMStructTypeKind || kind == LLVMArrayTypeKind) {
- args[i] = is_struct(c, t);
- } else {
- args[i] = non_struct(c, t, false);
- }
- }
- return args;
- }
- lbArgType compute_return_type(LLVMContextRef c, LLVMTypeRef return_type, bool return_is_defined) {
- if (!return_is_defined) {
- return lb_arg_type_direct(LLVMVoidTypeInContext(c));
- } else if (lb_is_type_kind(return_type, LLVMStructTypeKind) || lb_is_type_kind(return_type, LLVMArrayTypeKind)) {
- if (type_can_be_direct(return_type)) {
- return lb_arg_type_direct(return_type);
- }
- i64 sz = lb_sizeof(return_type);
- switch (sz) {
- case 1: return lb_arg_type_direct(return_type, LLVMIntTypeInContext(c, 8), nullptr, nullptr);
- case 2: return lb_arg_type_direct(return_type, LLVMIntTypeInContext(c, 16), nullptr, nullptr);
- 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_with_type(c, "sret", return_type);
- return lb_arg_type_indirect(return_type, attr);
- }
- return non_struct(c, return_type, true);
- }
- }
- namespace lbAbiArm32 {
- Array<lbArgType> compute_arg_types(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count, ProcCallingConvention calling_convention);
- lbArgType compute_return_type(LLVMContextRef c, LLVMTypeRef return_type, bool return_is_defined);
- LB_ABI_INFO(abi_info) {
- lbFunctionType *ft = gb_alloc_item(permanent_allocator(), lbFunctionType);
- ft->ctx = c;
- ft->args = compute_arg_types(c, arg_types, arg_count, calling_convention);
- ft->ret = compute_return_type(c, return_type, return_is_defined);
- ft->calling_convention = calling_convention;
- return ft;
- }
- bool is_register(LLVMTypeRef type, bool is_return) {
- LLVMTypeKind kind = LLVMGetTypeKind(type);
- switch (kind) {
- case LLVMHalfTypeKind:
- case LLVMFloatTypeKind:
- case LLVMDoubleTypeKind:
- return true;
- case LLVMIntegerTypeKind:
- return lb_sizeof(type) <= 8;
- case LLVMFunctionTypeKind:
- return true;
- case LLVMPointerTypeKind:
- return true;
- case LLVMVectorTypeKind:
- return true;
- }
- return false;
- }
- lbArgType non_struct(LLVMContextRef c, LLVMTypeRef type, bool is_return) {
- LLVMAttributeRef attr = nullptr;
- LLVMTypeRef i1 = LLVMInt1TypeInContext(c);
- if (type == i1) {
- attr = lb_create_enum_attribute(c, "zeroext");
- }
- return lb_arg_type_direct(type, nullptr, nullptr, attr);
- }
- Array<lbArgType> compute_arg_types(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count, ProcCallingConvention calling_convention) {
- auto args = array_make<lbArgType>(heap_allocator(), arg_count);
- for (unsigned i = 0; i < arg_count; i++) {
- LLVMTypeRef t = arg_types[i];
- if (is_register(t, false)) {
- args[i] = non_struct(c, t, false);
- } else {
- i64 sz = lb_sizeof(t);
- i64 a = lb_alignof(t);
- if (is_calling_convention_odin(calling_convention) && sz > 8) {
- // Minor change to improve performance using the Odin calling conventions
- args[i] = lb_arg_type_indirect(t, nullptr);
- } else if (a <= 4) {
- unsigned n = cast(unsigned)((sz + 3) / 4);
- args[i] = lb_arg_type_direct(LLVMArrayType(LLVMIntTypeInContext(c, 32), n));
- } else {
- unsigned n = cast(unsigned)((sz + 7) / 8);
- args[i] = lb_arg_type_direct(LLVMArrayType(LLVMIntTypeInContext(c, 64), n));
- }
- }
- }
- return args;
- }
- lbArgType compute_return_type(LLVMContextRef c, LLVMTypeRef return_type, bool return_is_defined) {
- if (!return_is_defined) {
- return lb_arg_type_direct(LLVMVoidTypeInContext(c));
- } else if (!is_register(return_type, true)) {
- switch (lb_sizeof(return_type)) {
- case 1: return lb_arg_type_direct(LLVMIntTypeInContext(c, 8), return_type, nullptr, nullptr);
- case 2: return lb_arg_type_direct(LLVMIntTypeInContext(c, 16), return_type, nullptr, nullptr);
- case 3: case 4: return lb_arg_type_direct(LLVMIntTypeInContext(c, 32), return_type, nullptr, nullptr);
- }
- 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);
- }
- };
- LB_ABI_INFO(lb_get_abi_info) {
- switch (calling_convention) {
- case ProcCC_None:
- case ProcCC_InlineAsm:
- {
- lbFunctionType *ft = gb_alloc_item(permanent_allocator(), lbFunctionType);
- ft->ctx = c;
- ft->args = array_make<lbArgType>(heap_allocator(), arg_count);
- for (unsigned i = 0; i < arg_count; i++) {
- ft->args[i] = lb_arg_type_direct(arg_types[i]);
- }
- if (return_is_defined) {
- ft->ret = lb_arg_type_direct(return_type);
- } else {
- ft->ret = lb_arg_type_direct(LLVMVoidTypeInContext(c));
- }
- ft->calling_convention = calling_convention;
- return ft;
- }
- case ProcCC_Win64:
- GB_ASSERT(build_context.metrics.arch == TargetArch_amd64);
- return lbAbiAmd64Win64::abi_info(c, arg_types, arg_count, return_type, return_is_defined, calling_convention);
- case ProcCC_SysV:
- GB_ASSERT(build_context.metrics.arch == TargetArch_amd64);
- return lbAbiAmd64SysV::abi_info(c, arg_types, arg_count, return_type, return_is_defined, calling_convention);
- }
- switch (build_context.metrics.arch) {
- case TargetArch_amd64:
- if (build_context.metrics.os == TargetOs_windows || build_context.metrics.abi == TargetABI_Win64) {
- return lbAbiAmd64Win64::abi_info(c, arg_types, arg_count, return_type, return_is_defined, calling_convention);
- } else if (build_context.metrics.abi == TargetABI_SysV) {
- return lbAbiAmd64SysV::abi_info(c, arg_types, arg_count, return_type, return_is_defined, calling_convention);
- } else {
- return lbAbiAmd64SysV::abi_info(c, arg_types, arg_count, return_type, return_is_defined, calling_convention);
- }
- case TargetArch_i386:
- return lbAbi386::abi_info(c, arg_types, arg_count, return_type, return_is_defined, calling_convention);
- case TargetArch_arm32:
- return lbAbiArm32::abi_info(c, arg_types, arg_count, return_type, return_is_defined, calling_convention);
- case TargetArch_arm64:
- return lbAbiArm64::abi_info(c, arg_types, arg_count, return_type, return_is_defined, calling_convention);
- case TargetArch_wasm32:
- case TargetArch_wasm64:
- return lbAbiWasm::abi_info(c, arg_types, arg_count, return_type, return_is_defined, calling_convention);
- }
- GB_PANIC("Unsupported ABI");
- return {};
- }
|