diff options
| author | Michael Lee <leecommamichael@gmail.com> | 2025-12-23 16:12:53 -0600 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-12-23 16:12:53 -0600 |
| commit | 550e57aba977ff766e5ab38a4c13a8dc18d55992 (patch) | |
| tree | 6704ea53d838f7d7427e5bf6faa1d586378869b3 /src | |
| parent | 729d0a8e8ace759d5d1358b14b20e19f68f44ff0 (diff) | |
| parent | 57352d9933785097e21c282807f5e845ec8f6d85 (diff) | |
Merge branch 'odin-lang:master' into core-image-tga
Diffstat (limited to 'src')
48 files changed, 5027 insertions, 1419 deletions
diff --git a/src/build_settings.cpp b/src/build_settings.cpp index 4bee0ad4e..7160f3721 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -418,6 +418,7 @@ enum LinkerChoice : i32 { Linker_Default = 0, Linker_lld, Linker_radlink, + Linker_mold, Linker_COUNT, }; @@ -433,6 +434,7 @@ String linker_choices[Linker_COUNT] = { str_lit("default"), str_lit("lld"), str_lit("radlink"), + str_lit("mold"), }; enum IntegerDivisionByZeroKind : u8 { @@ -507,6 +509,7 @@ struct BuildContext { bool show_more_timings; bool show_defineables; String export_defineables_file; + bool ignore_unused_defineables; bool show_system_calls; bool keep_temp_files; bool ignore_unknown_attributes; @@ -546,6 +549,8 @@ struct BuildContext { bool ignore_microsoft_magic; bool linker_map_file; + bool build_diagnostics; + bool use_single_module; bool use_separate_modules; bool module_per_file; @@ -554,6 +559,8 @@ struct BuildContext { bool internal_no_inline; bool internal_by_value; + bool internal_weak_monomorphization; + bool internal_ignore_llvm_verification; bool no_threaded_checker; @@ -569,6 +576,8 @@ struct BuildContext { bool min_link_libs; + String export_linked_libs_path; + bool print_linker_flags; RelocMode reloc_mode; @@ -826,7 +835,7 @@ gb_global TargetMetrics target_freestanding_amd64_win64 = { TargetOs_freestanding, TargetArch_amd64, 8, 8, AMD64_MAX_ALIGNMENT, 32, - str_lit("x86_64-pc-none-msvc"), + str_lit("x86_64-pc-windows-msvc"), TargetABI_Win64, }; @@ -964,14 +973,6 @@ gb_internal bool is_excluded_target_filename(String name) { return true; } - if (build_context.command_kind != Command_test) { - String test_suffix = str_lit("_test"); - if (string_ends_with(name, test_suffix) && name != test_suffix) { - // Ignore *_test.odin files - return true; - } - } - String str1 = {}; String str2 = {}; isize n = 0; @@ -1126,7 +1127,7 @@ gb_internal String internal_odin_root_dir(void) { mutex_lock(&string_buffer_mutex); defer (mutex_unlock(&string_buffer_mutex)); - text = gb_alloc_array(permanent_allocator(), wchar_t, len+1); + text = permanent_alloc_array<wchar_t>(len+1); GetModuleFileNameW(nullptr, text, cast(int)len); path = string16_to_string(heap_allocator(), make_string16(cast(u16 *)text, len)); @@ -1163,8 +1164,8 @@ gb_internal String internal_odin_root_dir(void) { return global_module_path; } - auto path_buf = array_make<char>(heap_allocator(), 300); - defer (array_free(&path_buf)); + TEMPORARY_ALLOCATOR_GUARD(); + auto path_buf = array_make<char>(temporary_allocator(), 300); len = 0; for (;;) { @@ -1181,7 +1182,7 @@ gb_internal String internal_odin_root_dir(void) { mutex_lock(&string_buffer_mutex); defer (mutex_unlock(&string_buffer_mutex)); - text = gb_alloc_array(permanent_allocator(), u8, len + 1); + text = permanent_alloc_array<u8>(len + 1); gb_memmove(text, &path_buf[0], len); path = path_to_fullpath(heap_allocator(), make_string(text, len), nullptr); @@ -1233,7 +1234,7 @@ gb_internal String internal_odin_root_dir(void) { mutex_lock(&string_buffer_mutex); defer (mutex_unlock(&string_buffer_mutex)); - text = gb_alloc_array(permanent_allocator(), u8, len + 1); + text = permanent_alloc_array<u8>(len + 1); gb_memmove(text, &path_buf[0], len); path = path_to_fullpath(heap_allocator(), make_string(text, len), nullptr); @@ -1394,7 +1395,7 @@ gb_internal String internal_odin_root_dir(void) { mutex_lock(&string_buffer_mutex); defer (mutex_unlock(&string_buffer_mutex)); - text = gb_alloc_array(permanent_allocator(), u8, len + 1); + text = permanent_alloc_array<u8>(len + 1); gb_memmove(text, &path_buf[0], len); @@ -1429,7 +1430,7 @@ gb_internal String path_to_fullpath(gbAllocator a, String s, bool *ok_) { len = GetFullPathNameW(cast(wchar_t *)&string16[0], 0, nullptr, nullptr); if (len != 0) { - wchar_t *text = gb_alloc_array(permanent_allocator(), wchar_t, len+1); + wchar_t *text = permanent_alloc_array<wchar_t>(len+1); GetFullPathNameW(cast(wchar_t *)&string16[0], len, text, nullptr); mutex_unlock(&fullpath_mutex); @@ -2095,7 +2096,19 @@ gb_internal bool check_target_feature_is_enabled(String const &feature, String * for (;;) { String str = string_split_iterator(&it, ','); if (str == "") break; + if (!string_set_exists(&build_context.target_features_set, str)) { + String plus_str = concatenate_strings(temporary_allocator(), make_string_c("+"), str); + + if (!string_set_exists(&build_context.target_features_set, plus_str)) { + if (not_enabled) *not_enabled = str; + return false; + } + } + + String minus_str = concatenate_strings(temporary_allocator(), make_string_c("-"), str); + + if (string_set_exists(&build_context.target_features_set, minus_str)) { if (not_enabled) *not_enabled = str; return false; } diff --git a/src/build_settings_microarch.cpp b/src/build_settings_microarch.cpp index 16fb2196f..0755aa62d 100644 --- a/src/build_settings_microarch.cpp +++ b/src/build_settings_microarch.cpp @@ -2,7 +2,581 @@ #error "LLVM_VERSION_MAJOR is not defined!" #endif -#if LLVM_VERSION_MAJOR >= 20 +#if LLVM_VERSION_MAJOR >= 21 +// Generated with the featuregen script in `misc/featuregen` +gb_global String target_microarch_list[TargetArch_COUNT] = { + // TargetArch_Invalid: + str_lit(""), + // TargetArch_amd64: + str_lit("alderlake,amdfam10,arrowlake,arrowlake-s,arrowlake_s,athlon,athlon-4,athlon-fx,athlon-mp,athlon-tbird,athlon-xp,athlon64,athlon64-sse3,atom,atom_sse4_2,atom_sse4_2_movbe,barcelona,bdver1,bdver2,bdver3,bdver4,bonnell,broadwell,btver1,btver2,c3,c3-2,cannonlake,cascadelake,clearwaterforest,cooperlake,core-avx-i,core-avx2,core2,core_2_duo_sse4_1,core_2_duo_ssse3,core_2nd_gen_avx,core_3rd_gen_avx,core_4th_gen_avx,core_4th_gen_avx_tsx,core_5th_gen_avx,core_5th_gen_avx_tsx,core_aes_pclmulqdq,core_i7_sse4_2,corei7,corei7-avx,diamondrapids,emeraldrapids,generic,geode,goldmont,goldmont-plus,goldmont_plus,gracemont,grandridge,graniterapids,graniterapids-d,graniterapids_d,haswell,i386,i486,i586,i686,icelake-client,icelake-server,icelake_client,icelake_server,ivybridge,k6,k6-2,k6-3,k8,k8-sse3,knl,knm,lakemont,lunarlake,meteorlake,mic_avx512,nehalem,nocona,opteron,opteron-sse3,pantherlake,penryn,pentium,pentium-m,pentium-mmx,pentium2,pentium3,pentium3m,pentium4,pentium4m,pentium_4,pentium_4_sse3,pentium_ii,pentium_iii,pentium_iii_no_xmm_regs,pentium_m,pentium_mmx,pentium_pro,pentiumpro,prescott,raptorlake,rocketlake,sandybridge,sapphirerapids,sierraforest,silvermont,skx,skylake,skylake-avx512,skylake_avx512,slm,tigerlake,tremont,westmere,winchip-c6,winchip2,x86-64,x86-64-v2,x86-64-v3,x86-64-v4,yonah,znver1,znver2,znver3,znver4,znver5"), + // TargetArch_i386: + str_lit("alderlake,amdfam10,arrowlake,arrowlake-s,arrowlake_s,athlon,athlon-4,athlon-fx,athlon-mp,athlon-tbird,athlon-xp,athlon64,athlon64-sse3,atom,atom_sse4_2,atom_sse4_2_movbe,barcelona,bdver1,bdver2,bdver3,bdver4,bonnell,broadwell,btver1,btver2,c3,c3-2,cannonlake,cascadelake,clearwaterforest,cooperlake,core-avx-i,core-avx2,core2,core_2_duo_sse4_1,core_2_duo_ssse3,core_2nd_gen_avx,core_3rd_gen_avx,core_4th_gen_avx,core_4th_gen_avx_tsx,core_5th_gen_avx,core_5th_gen_avx_tsx,core_aes_pclmulqdq,core_i7_sse4_2,corei7,corei7-avx,diamondrapids,emeraldrapids,generic,geode,goldmont,goldmont-plus,goldmont_plus,gracemont,grandridge,graniterapids,graniterapids-d,graniterapids_d,haswell,i386,i486,i586,i686,icelake-client,icelake-server,icelake_client,icelake_server,ivybridge,k6,k6-2,k6-3,k8,k8-sse3,knl,knm,lakemont,lunarlake,meteorlake,mic_avx512,nehalem,nocona,opteron,opteron-sse3,pantherlake,penryn,pentium,pentium-m,pentium-mmx,pentium2,pentium3,pentium3m,pentium4,pentium4m,pentium_4,pentium_4_sse3,pentium_ii,pentium_iii,pentium_iii_no_xmm_regs,pentium_m,pentium_mmx,pentium_pro,pentiumpro,prescott,raptorlake,rocketlake,sandybridge,sapphirerapids,sierraforest,silvermont,skx,skylake,skylake-avx512,skylake_avx512,slm,tigerlake,tremont,westmere,winchip-c6,winchip2,x86-64,x86-64-v2,x86-64-v3,x86-64-v4,yonah,znver1,znver2,znver3,znver4,znver5"), + // TargetArch_arm32: + str_lit("arm1020e,arm1020t,arm1022e,arm10e,arm10tdmi,arm1136j-s,arm1136jf-s,arm1156t2-s,arm1156t2f-s,arm1176jz-s,arm1176jzf-s,arm710t,arm720t,arm7tdmi,arm7tdmi-s,arm8,arm810,arm9,arm920,arm920t,arm922t,arm926ej-s,arm940t,arm946e-s,arm966e-s,arm968e-s,arm9e,arm9tdmi,cortex-a12,cortex-a15,cortex-a17,cortex-a32,cortex-a35,cortex-a5,cortex-a510,cortex-a53,cortex-a55,cortex-a57,cortex-a7,cortex-a710,cortex-a72,cortex-a73,cortex-a75,cortex-a76,cortex-a76ae,cortex-a77,cortex-a78,cortex-a78ae,cortex-a78c,cortex-a8,cortex-a9,cortex-m0,cortex-m0plus,cortex-m1,cortex-m23,cortex-m3,cortex-m33,cortex-m35p,cortex-m4,cortex-m52,cortex-m55,cortex-m7,cortex-m85,cortex-r4,cortex-r4f,cortex-r5,cortex-r52,cortex-r52plus,cortex-r7,cortex-r8,cortex-x1,cortex-x1c,cyclone,ep9312,exynos-m3,exynos-m4,exynos-m5,generic,iwmmxt,krait,kryo,mpcore,mpcorenovfp,neoverse-n1,neoverse-n2,neoverse-v1,sc000,sc300,star-mc1,strongarm,strongarm110,strongarm1100,strongarm1110,swift,xscale"), + // TargetArch_arm64: + str_lit("a64fx,ampere1,ampere1a,ampere1b,apple-a10,apple-a11,apple-a12,apple-a13,apple-a14,apple-a15,apple-a16,apple-a17,apple-a18,apple-a7,apple-a8,apple-a9,apple-m1,apple-m2,apple-m3,apple-m4,apple-s10,apple-s4,apple-s5,apple-s6,apple-s7,apple-s8,apple-s9,carmel,cobalt-100,cortex-a320,cortex-a34,cortex-a35,cortex-a510,cortex-a520,cortex-a520ae,cortex-a53,cortex-a55,cortex-a57,cortex-a65,cortex-a65ae,cortex-a710,cortex-a715,cortex-a72,cortex-a720,cortex-a720ae,cortex-a725,cortex-a73,cortex-a75,cortex-a76,cortex-a76ae,cortex-a77,cortex-a78,cortex-a78ae,cortex-a78c,cortex-r82,cortex-r82ae,cortex-x1,cortex-x1c,cortex-x2,cortex-x3,cortex-x4,cortex-x925,cyclone,exynos-m3,exynos-m4,exynos-m5,falkor,fujitsu-monaka,gb10,generic,grace,kryo,neoverse-512tvb,neoverse-e1,neoverse-n1,neoverse-n2,neoverse-n3,neoverse-v1,neoverse-v2,neoverse-v3,neoverse-v3ae,olympus,oryon-1,saphira,thunderx,thunderx2t99,thunderx3t110,thunderxt81,thunderxt83,thunderxt88,tsv110"), + // TargetArch_wasm32: + str_lit("bleeding-edge,generic,lime1,mvp"), + // TargetArch_wasm64p32: + str_lit("bleeding-edge,generic,lime1,mvp"), + // TargetArch_riscv64: + str_lit("andes-45-series,andes-a25,andes-a45,andes-ax25,andes-ax45,andes-ax45mpv,andes-n45,andes-nx45,generic,generic-ooo,generic-rv32,generic-rv64,mips-p8700,rocket,rocket-rv32,rocket-rv64,rp2350-hazard3,sifive-7-series,sifive-e20,sifive-e21,sifive-e24,sifive-e31,sifive-e34,sifive-e76,sifive-p450,sifive-p470,sifive-p550,sifive-p670,sifive-p870,sifive-s21,sifive-s51,sifive-s54,sifive-s76,sifive-u54,sifive-u74,sifive-x280,sifive-x390,spacemit-x60,syntacore-scr1-base,syntacore-scr1-max,syntacore-scr3-rv32,syntacore-scr3-rv64,syntacore-scr4-rv32,syntacore-scr4-rv64,syntacore-scr5-rv32,syntacore-scr5-rv64,syntacore-scr7,tt-ascalon-d8,veyron-v1,xiangshan-kunminghu,xiangshan-nanhu"), +}; + +// Generated with the featuregen script in `misc/featuregen` +gb_global String target_features_list[TargetArch_COUNT] = { + // TargetArch_Invalid: + str_lit(""), + // TargetArch_amd64: + str_lit("16bit-mode,32bit-mode,64bit,64bit-mode,adx,aes,allow-light-256-bit,amx-avx512,amx-bf16,amx-complex,amx-fp16,amx-fp8,amx-int8,amx-movrs,amx-tf32,amx-tile,amx-transpose,avx,avx10.1-256,avx10.1-512,avx10.2-256,avx10.2-512,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512fp16,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vp2intersect,avx512vpopcntdq,avxifma,avxneconvert,avxvnni,avxvnniint16,avxvnniint8,bmi,bmi2,branch-hint,branchfusion,ccmp,cf,cldemote,clflushopt,clwb,clzero,cmov,cmpccxadd,crc32,cx16,cx8,egpr,enqcmd,ermsb,evex512,f16c,false-deps-getmant,false-deps-lzcnt-tzcnt,false-deps-mulc,false-deps-mullq,false-deps-perm,false-deps-popcnt,false-deps-range,fast-11bytenop,fast-15bytenop,fast-7bytenop,fast-bextr,fast-dpwssd,fast-gather,fast-hops,fast-imm16,fast-lzcnt,fast-movbe,fast-scalar-fsqrt,fast-scalar-shift-masks,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fast-vector-shift-masks,faster-shift-than-shuffle,fma,fma4,fsgsbase,fsrm,fxsr,gfni,harden-sls-ijmp,harden-sls-ret,hreset,idivl-to-divb,idivq-to-divl,inline-asm-use-gpr32,invpcid,kl,lea-sp,lea-uses-ag,lvi-cfi,lvi-load-hardening,lwp,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,movrs,mwaitx,ndd,nf,no-bypass-delay,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pad-short-functions,pclmul,pconfig,pku,popcnt,ppx,prefer-128-bit,prefer-256-bit,prefer-mask-registers,prefer-movmsk-over-vtest,prefer-no-gather,prefer-no-scatter,prefetchi,prfchw,ptwrite,push2pop2,raoint,rdpid,rdpru,rdrnd,rdseed,retpoline,retpoline-external-thunk,retpoline-indirect-branches,retpoline-indirect-calls,rtm,sahf,sbb-dep-breaking,serialize,seses,sgx,sha,sha512,shstk,slow-3ops-lea,slow-incdec,slow-lea,slow-pmaddwd,slow-pmulld,slow-shld,slow-two-mem-ops,slow-unaligned-mem-16,slow-unaligned-mem-32,sm3,sm4,soft-float,sse,sse-unaligned-mem,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,tagged-globals,tbm,tsxldtrk,tuning-fast-imm-vector-shift,uintr,use-glm-div-sqrt-costs,use-slm-arith-costs,usermsr,vaes,vpclmulqdq,vzeroupper,waitpkg,wbnoinvd,widekl,x87,xop,xsave,xsavec,xsaveopt,xsaves,zu"), + // TargetArch_i386: + str_lit("16bit-mode,32bit-mode,64bit,64bit-mode,adx,aes,allow-light-256-bit,amx-avx512,amx-bf16,amx-complex,amx-fp16,amx-fp8,amx-int8,amx-movrs,amx-tf32,amx-tile,amx-transpose,avx,avx10.1-256,avx10.1-512,avx10.2-256,avx10.2-512,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512fp16,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vp2intersect,avx512vpopcntdq,avxifma,avxneconvert,avxvnni,avxvnniint16,avxvnniint8,bmi,bmi2,branch-hint,branchfusion,ccmp,cf,cldemote,clflushopt,clwb,clzero,cmov,cmpccxadd,crc32,cx16,cx8,egpr,enqcmd,ermsb,evex512,f16c,false-deps-getmant,false-deps-lzcnt-tzcnt,false-deps-mulc,false-deps-mullq,false-deps-perm,false-deps-popcnt,false-deps-range,fast-11bytenop,fast-15bytenop,fast-7bytenop,fast-bextr,fast-dpwssd,fast-gather,fast-hops,fast-imm16,fast-lzcnt,fast-movbe,fast-scalar-fsqrt,fast-scalar-shift-masks,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fast-vector-shift-masks,faster-shift-than-shuffle,fma,fma4,fsgsbase,fsrm,fxsr,gfni,harden-sls-ijmp,harden-sls-ret,hreset,idivl-to-divb,idivq-to-divl,inline-asm-use-gpr32,invpcid,kl,lea-sp,lea-uses-ag,lvi-cfi,lvi-load-hardening,lwp,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,movrs,mwaitx,ndd,nf,no-bypass-delay,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pad-short-functions,pclmul,pconfig,pku,popcnt,ppx,prefer-128-bit,prefer-256-bit,prefer-mask-registers,prefer-movmsk-over-vtest,prefer-no-gather,prefer-no-scatter,prefetchi,prfchw,ptwrite,push2pop2,raoint,rdpid,rdpru,rdrnd,rdseed,retpoline,retpoline-external-thunk,retpoline-indirect-branches,retpoline-indirect-calls,rtm,sahf,sbb-dep-breaking,serialize,seses,sgx,sha,sha512,shstk,slow-3ops-lea,slow-incdec,slow-lea,slow-pmaddwd,slow-pmulld,slow-shld,slow-two-mem-ops,slow-unaligned-mem-16,slow-unaligned-mem-32,sm3,sm4,soft-float,sse,sse-unaligned-mem,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,tagged-globals,tbm,tsxldtrk,tuning-fast-imm-vector-shift,uintr,use-glm-div-sqrt-costs,use-slm-arith-costs,usermsr,vaes,vpclmulqdq,vzeroupper,waitpkg,wbnoinvd,widekl,x87,xop,xsave,xsavec,xsaveopt,xsaves,zu"), + // TargetArch_arm32: + str_lit("32bit,8msecext,a12,a15,a17,a32,a35,a5,a53,a55,a57,a7,a72,a73,a75,a76,a77,a78c,a8,a9,aapcs-frame-chain,aclass,acquire-release,aes,armv4,armv4t,armv5t,armv5te,armv5tej,armv6,armv6-m,armv6j,armv6k,armv6kz,armv6s-m,armv6t2,armv7-a,armv7-m,armv7-r,armv7e-m,armv7k,armv7s,armv7ve,armv8-a,armv8-m.base,armv8-m.main,armv8-r,armv8.1-a,armv8.1-m.main,armv8.2-a,armv8.3-a,armv8.4-a,armv8.5-a,armv8.6-a,armv8.7-a,armv8.8-a,armv8.9-a,armv9-a,armv9.1-a,armv9.2-a,armv9.3-a,armv9.4-a,armv9.5-a,armv9.6-a,atomics-32,avoid-movs-shop,avoid-muls,avoid-partial-cpsr,bf16,big-endian-instructions,branch-align-64,cde,cdecp0,cdecp1,cdecp2,cdecp3,cdecp4,cdecp5,cdecp6,cdecp7,cheap-predicable-cpsr,clrbhb,cortex-a510,cortex-a710,cortex-a78,cortex-a78ae,cortex-x1,cortex-x1c,crc,crypto,d32,db,dfb,disable-postra-scheduler,dont-widen-vmovs,dotprod,dsp,execute-only,expand-fp-mlx,exynos,fix-cmse-cve-2021-35465,fix-cortex-a57-aes-1742098,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp16fml,fp64,fpao,fpregs,fpregs16,fpregs64,fullfp16,fuse-aes,fuse-literals,harden-sls-blr,harden-sls-nocomdat,harden-sls-retbr,hwdiv,hwdiv-arm,i8mm,iwmmxt,iwmmxt2,krait,kryo,lob,long-calls,loop-align,m3,m55,m7,m85,mclass,mp,muxed-units,mve,mve.fp,mve1beat,mve2beat,mve4beat,nacl-trap,neon,neon-fpmovs,neonfp,neoverse-v1,no-branch-predictor,no-bti-at-return-twice,no-movt,no-neg-immediates,noarm,nonpipelined-vfp,pacbti,perfmon,prefer-ishst,prefer-vmovsr,prof-unpr,r4,r5,r52,r52plus,r7,ras,rclass,read-tp-tpidrprw,read-tp-tpidruro,read-tp-tpidrurw,reserve-r9,ret-addr-stack,sb,sha2,slow-fp-brcc,slow-load-D-subreg,slow-odd-reg,slow-vdup32,slow-vgetlni32,slowfpvfmx,slowfpvmlx,soft-float,splat-vfp-neon,strict-align,swift,thumb-mode,thumb2,trustzone,use-mipipeliner,use-misched,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.1m.main,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8.7a,v8.8a,v8.9a,v8m,v8m.main,v9.1a,v9.2a,v9.3a,v9.4a,v9.5a,v9.6a,v9a,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization,vldn-align,vmlx-forwarding,vmlx-hazards,wide-stride-vfp,xscale,zcz"), + // TargetArch_arm64: + str_lit("CONTEXTIDREL2,a320,a35,a510,a520,a520ae,a53,a55,a57,a64fx,a65,a710,a715,a72,a720,a720ae,a73,a75,a76,a77,a78,a78ae,a78c,addr-lsl-slow-14,aes,aggressive-fma,all,alternate-sextload-cvt-f32-pattern,altnzcv,alu-lsl-fast,am,ampere1,ampere1a,ampere1b,amvs,apple-a10,apple-a11,apple-a12,apple-a13,apple-a14,apple-a15,apple-a16,apple-a17,apple-a7,apple-m4,arith-bcc-fusion,arith-cbz-fusion,ascend-store-address,avoid-ldapur,balance-fp-ops,bf16,brbe,bti,call-saved-x10,call-saved-x11,call-saved-x12,call-saved-x13,call-saved-x14,call-saved-x15,call-saved-x18,call-saved-x8,call-saved-x9,carmel,ccdp,ccidx,ccpp,chk,clrbhb,cmp-bcc-fusion,cmpbr,complxnum,cortex-a725,cortex-r82,cortex-r82ae,cortex-x1,cortex-x2,cortex-x3,cortex-x4,cortex-x925,cpa,crc,crypto,cssc,d128,disable-fast-inc-vl,disable-latency-sched-heuristic,disable-ldp,disable-stp,dit,dotprod,ecv,el2vmsa,el3,enable-select-opt,ete,execute-only,exynos-cheap-as-move,exynosm3,exynosm4,f32mm,f64mm,f8f16mm,f8f32mm,falkor,faminmax,fgt,fix-cortex-a53-835769,flagm,fmv,force-32bit-jump-tables,fp-armv8,fp16fml,fp8,fp8dot2,fp8dot4,fp8fma,fpac,fprcvt,fptoint,fujitsu-monaka,fullfp16,fuse-address,fuse-addsub-2reg-const1,fuse-adrp-add,fuse-aes,fuse-arith-logic,fuse-crypto-eor,fuse-csel,fuse-literals,gcs,harden-sls-blr,harden-sls-nocomdat,harden-sls-retbr,hbc,hcx,i8mm,ite,jsconv,kryo,ldp-aligned-only,lor,ls64,lse,lse128,lse2,lsfe,lsui,lut,mec,mops,mpam,mte,neon,neoverse512tvb,neoversee1,neoversen1,neoversen2,neoversen3,neoversev1,neoversev2,neoversev3,neoversev3AE,nmi,no-bti-at-return-twice,no-neg-immediates,no-sve-fp-ld1r,no-zcz-fp,nv,occmo,olympus,oryon-1,outline-atomics,pan,pan-rwv,pauth,pauth-lr,pcdphint,perfmon,pops,predictable-select-expensive,predres,prfm-slc-target,rand,ras,rasv2,rcpc,rcpc-immo,rcpc3,rdm,reserve-lr-for-ra,reserve-x1,reserve-x10,reserve-x11,reserve-x12,reserve-x13,reserve-x14,reserve-x15,reserve-x18,reserve-x2,reserve-x20,reserve-x21,reserve-x22,reserve-x23,reserve-x24,reserve-x25,reserve-x26,reserve-x27,reserve-x28,reserve-x3,reserve-x4,reserve-x5,reserve-x6,reserve-x7,reserve-x9,rme,saphira,sb,sel2,sha2,sha3,slow-misaligned-128store,slow-paired-128,slow-strqro-store,sm4,sme,sme-b16b16,sme-f16f16,sme-f64f64,sme-f8f16,sme-f8f32,sme-fa64,sme-i16i64,sme-lutv2,sme-mop4,sme-tmop,sme2,sme2p1,sme2p2,spe,spe-eef,specres2,specrestrict,ssbs,ssve-aes,ssve-bitperm,ssve-fexpa,ssve-fp8dot2,ssve-fp8dot4,ssve-fp8fma,store-pair-suppress,stp-aligned-only,strict-align,sve,sve-aes,sve-aes2,sve-b16b16,sve-bfscale,sve-bitperm,sve-f16f32mm,sve-sha3,sve-sm4,sve2,sve2-aes,sve2-bitperm,sve2-sha3,sve2-sm4,sve2p1,sve2p2,tagged-globals,the,thunderx,thunderx2t99,thunderx3t110,thunderxt81,thunderxt83,thunderxt88,tlb-rmi,tlbiw,tme,tpidr-el1,tpidr-el2,tpidr-el3,tpidrro-el0,tracev8.4,trbe,tsv110,uaops,use-experimental-zeroing-pseudos,use-fixed-over-scalable-if-equal-cost,use-postra-scheduler,use-reciprocal-square-root,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8.7a,v8.8a,v8.9a,v8a,v8r,v9.1a,v9.2a,v9.3a,v9.4a,v9.5a,v9.6a,v9a,vh,wfxt,xs,zcm-fpr32,zcm-fpr64,zcm-gpr32,zcm-gpr64,zcz,zcz-fp-workaround,zcz-gp"), + // TargetArch_wasm32: + str_lit("atomics,bulk-memory,bulk-memory-opt,call-indirect-overlong,exception-handling,extended-const,fp16,multimemory,multivalue,mutable-globals,nontrapping-fptoint,reference-types,relaxed-simd,sign-ext,simd128,tail-call,wide-arithmetic"), + // TargetArch_wasm64p32: + str_lit("atomics,bulk-memory,bulk-memory-opt,call-indirect-overlong,exception-handling,extended-const,fp16,multimemory,multivalue,mutable-globals,nontrapping-fptoint,reference-types,relaxed-simd,sign-ext,simd128,tail-call,wide-arithmetic"), + // TargetArch_riscv64: + str_lit("32bit,64bit,a,andes45,auipc-addi-fusion,b,c,conditional-cmv-fusion,d,disable-latency-sched-heuristic,dlen-factor-2,e,exact-asm,experimental,experimental-p,experimental-rvm23u32,experimental-smctr,experimental-ssctr,experimental-svukte,experimental-xqccmp,experimental-xqcia,experimental-xqciac,experimental-xqcibi,experimental-xqcibm,experimental-xqcicli,experimental-xqcicm,experimental-xqcics,experimental-xqcicsr,experimental-xqciint,experimental-xqciio,experimental-xqcilb,experimental-xqcili,experimental-xqcilia,experimental-xqcilo,experimental-xqcilsm,experimental-xqcisim,experimental-xqcisls,experimental-xqcisync,experimental-xrivosvisni,experimental-xrivosvizip,experimental-xsfmclic,experimental-xsfsclic,experimental-zalasr,experimental-zicfilp,experimental-zicfiss,experimental-zvbc32e,experimental-zvkgs,experimental-zvqdotq,f,forced-atomics,h,i,ld-add-fusion,log-vrgather,lui-addi-fusion,m,mips-p8700,no-default-unroll,no-sink-splat-operands,no-trailing-seq-cst-fence,optimized-nf2-segment-load-store,optimized-nf3-segment-load-store,optimized-nf4-segment-load-store,optimized-nf5-segment-load-store,optimized-nf6-segment-load-store,optimized-nf7-segment-load-store,optimized-nf8-segment-load-store,optimized-zero-stride-load,predictable-select-expensive,prefer-vsetvli-over-read-vlenb,prefer-w-inst,q,relax,reserve-x1,reserve-x10,reserve-x11,reserve-x12,reserve-x13,reserve-x14,reserve-x15,reserve-x16,reserve-x17,reserve-x18,reserve-x19,reserve-x2,reserve-x20,reserve-x21,reserve-x22,reserve-x23,reserve-x24,reserve-x25,reserve-x26,reserve-x27,reserve-x28,reserve-x29,reserve-x3,reserve-x30,reserve-x31,reserve-x4,reserve-x5,reserve-x6,reserve-x7,reserve-x8,reserve-x9,rva20s64,rva20u64,rva22s64,rva22u64,rva23s64,rva23u64,rvb23s64,rvb23u64,rvi20u32,rvi20u64,save-restore,sdext,sdtrig,sha,shcounterenw,shgatpa,shifted-zextw-fusion,shlcofideleg,short-forward-branch-opt,shtvala,shvsatpa,shvstvala,shvstvecd,sifive7,smaia,smcdeleg,smcntrpmf,smcsrind,smdbltrp,smepmp,smmpm,smnpm,smrnmi,smstateen,ssaia,ssccfg,ssccptr,sscofpmf,sscounterenw,sscsrind,ssdbltrp,ssnpm,sspm,ssqosid,ssstateen,ssstrict,sstc,sstvala,sstvecd,ssu64xl,supm,svade,svadu,svbare,svinval,svnapot,svpbmt,svvptc,tagged-globals,unaligned-scalar-mem,unaligned-vector-mem,use-postra-scheduler,v,ventana-veyron,vl-dependent-latency,vxrm-pipeline-flush,xandesbfhcvt,xandesperf,xandesvbfhcvt,xandesvdot,xandesvpackfph,xandesvsintload,xcvalu,xcvbi,xcvbitmanip,xcvelw,xcvmac,xcvmem,xcvsimd,xmipscbop,xmipscmov,xmipslsp,xsfcease,xsfmm128t,xsfmm16t,xsfmm32a16f,xsfmm32a32f,xsfmm32a8f,xsfmm32a8i,xsfmm32t,xsfmm64a64f,xsfmm64t,xsfmmbase,xsfvcp,xsfvfnrclipxfqf,xsfvfwmaccqqq,xsfvqmaccdod,xsfvqmaccqoq,xsifivecdiscarddlone,xsifivecflushdlone,xtheadba,xtheadbb,xtheadbs,xtheadcmo,xtheadcondmov,xtheadfmemidx,xtheadmac,xtheadmemidx,xtheadmempair,xtheadsync,xtheadvdot,xventanacondops,xwchc,za128rs,za64rs,zaamo,zabha,zacas,zalrsc,zama16b,zawrs,zba,zbb,zbc,zbkb,zbkc,zbkx,zbs,zca,zcb,zcd,zce,zcf,zclsd,zcmop,zcmp,zcmt,zdinx,zexth-fusion,zextw-fusion,zfa,zfbfmin,zfh,zfhmin,zfinx,zhinx,zhinxmin,zic64b,zicbom,zicbop,zicboz,ziccamoa,ziccamoc,ziccif,zicclsm,ziccrse,zicntr,zicond,zicsr,zifencei,zihintntl,zihintpause,zihpm,zilsd,zimop,zk,zkn,zknd,zkne,zknh,zkr,zks,zksed,zksh,zkt,zmmul,ztso,zvbb,zvbc,zve32f,zve32x,zve64d,zve64f,zve64x,zvfbfmin,zvfbfwma,zvfh,zvfhmin,zvkb,zvkg,zvkn,zvknc,zvkned,zvkng,zvknha,zvknhb,zvks,zvksc,zvksed,zvksg,zvksh,zvkt,zvl1024b,zvl128b,zvl16384b,zvl2048b,zvl256b,zvl32768b,zvl32b,zvl4096b,zvl512b,zvl64b,zvl65536b,zvl8192b"), +}; + +// Generated with the featuregen script in `misc/featuregen` +gb_global int target_microarch_counts[TargetArch_COUNT] = { + // TargetArch_Invalid: + 0, + // TargetArch_amd64: + 129, + // TargetArch_i386: + 129, + // TargetArch_arm32: + 95, + // TargetArch_arm64: + 91, + // TargetArch_wasm32: + 4, + // TargetArch_wasm64p32: + 4, + // TargetArch_riscv64: + 51, +}; + +// Generated with the featuregen script in `misc/featuregen` +gb_global MicroarchFeatureList microarch_features_list[] = { + // TargetArch_amd64: + { str_lit("alderlake"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avxvnni,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,f16c,false-deps-perm,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-movmsk-over-vtest,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("amdfam10"), str_lit("64bit,64bit-mode,cmov,cx16,cx8,fast-scalar-shift-masks,fxsr,idivq-to-divl,lzcnt,nopl,popcnt,prfchw,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4a,vzeroupper,x87") }, + { str_lit("arrowlake"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avxifma,avxneconvert,avxvnni,avxvnniint8,bmi,bmi2,clflushopt,clwb,cmov,cmpccxadd,crc32,cx16,cx8,enqcmd,f16c,false-deps-perm,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-movmsk-over-vtest,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("arrowlake-s"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avxifma,avxneconvert,avxvnni,avxvnniint16,avxvnniint8,bmi,bmi2,clflushopt,clwb,cmov,cmpccxadd,crc32,cx16,cx8,enqcmd,f16c,false-deps-perm,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-movmsk-over-vtest,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,sha512,shstk,slow-3ops-lea,sm3,sm4,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("arrowlake_s"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avxifma,avxneconvert,avxvnni,avxvnniint16,avxvnniint8,bmi,bmi2,clflushopt,clwb,cmov,cmpccxadd,crc32,cx16,cx8,enqcmd,f16c,false-deps-perm,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-movmsk-over-vtest,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,sha512,shstk,slow-3ops-lea,sm3,sm4,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("athlon"), str_lit("64bit-mode,cmov,cx8,mmx,nopl,prfchw,slow-shld,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("athlon-4"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,prfchw,slow-shld,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("athlon-fx"), str_lit("64bit,64bit-mode,cmov,cx8,fast-scalar-shift-masks,fxsr,mmx,nopl,prfchw,sbb-dep-breaking,slow-shld,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("athlon-mp"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,prfchw,slow-shld,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("athlon-tbird"), str_lit("64bit-mode,cmov,cx8,mmx,nopl,prfchw,slow-shld,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("athlon-xp"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,prfchw,slow-shld,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("athlon64"), str_lit("64bit,64bit-mode,cmov,cx8,fast-scalar-shift-masks,fxsr,mmx,nopl,prfchw,sbb-dep-breaking,slow-shld,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("athlon64-sse3"), str_lit("64bit,64bit-mode,cmov,cx16,cx8,fast-scalar-shift-masks,fxsr,mmx,nopl,prfchw,sbb-dep-breaking,slow-shld,slow-unaligned-mem-16,sse,sse2,sse3,vzeroupper,x87") }, + { str_lit("atom"), str_lit("64bit,64bit-mode,cmov,cx16,cx8,fast-imm16,fxsr,idivl-to-divb,idivq-to-divl,lea-sp,lea-uses-ag,mmx,movbe,no-bypass-delay,nopl,pad-short-functions,sahf,slow-two-mem-ops,slow-unaligned-mem-16,sse,sse2,sse3,ssse3,vzeroupper,x87") }, + { str_lit("atom_sse4_2"), str_lit("64bit,64bit-mode,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-7bytenop,fast-imm16,fast-movbe,fxsr,idivq-to-divl,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,rdrnd,sahf,slow-incdec,slow-lea,slow-pmulld,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-slm-arith-costs,vzeroupper,x87") }, + { str_lit("atom_sse4_2_movbe"), str_lit("64bit,64bit-mode,aes,clflushopt,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-7bytenop,fast-imm16,fast-movbe,fsgsbase,fxsr,idivq-to-divl,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,rdrnd,rdseed,sahf,sha,slow-incdec,slow-lea,slow-pmulld,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-slm-arith-costs,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("barcelona"), str_lit("64bit,64bit-mode,cmov,cx16,cx8,fast-scalar-shift-masks,fxsr,idivq-to-divl,lzcnt,nopl,popcnt,prfchw,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4a,vzeroupper,x87") }, + { str_lit("bdver1"), str_lit("64bit,64bit-mode,aes,avx,branchfusion,cmov,crc32,cx16,cx8,fast-11bytenop,fast-scalar-shift-masks,fma4,fxsr,idivq-to-divl,lwp,lzcnt,mmx,nopl,pclmul,popcnt,prfchw,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,vzeroupper,x87,xop,xsave") }, + { str_lit("bdver2"), str_lit("64bit,64bit-mode,aes,avx,bmi,branchfusion,cmov,crc32,cx16,cx8,f16c,fast-11bytenop,fast-bextr,fast-movbe,fast-scalar-shift-masks,fma,fma4,fxsr,idivq-to-divl,lwp,lzcnt,mmx,nopl,pclmul,popcnt,prfchw,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,tbm,vzeroupper,x87,xop,xsave") }, + { str_lit("bdver3"), str_lit("64bit,64bit-mode,aes,avx,bmi,branchfusion,cmov,crc32,cx16,cx8,f16c,fast-11bytenop,fast-bextr,fast-movbe,fast-scalar-shift-masks,fma,fma4,fsgsbase,fxsr,idivq-to-divl,lwp,lzcnt,mmx,nopl,pclmul,popcnt,prfchw,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,tbm,vzeroupper,x87,xop,xsave,xsaveopt") }, + { str_lit("bdver4"), str_lit("64bit,64bit-mode,aes,avx,avx2,bmi,bmi2,branchfusion,cmov,crc32,cx16,cx8,f16c,fast-11bytenop,fast-bextr,fast-movbe,fast-scalar-shift-masks,fma,fma4,fsgsbase,fxsr,idivq-to-divl,lwp,lzcnt,mmx,movbe,mwaitx,nopl,pclmul,popcnt,prfchw,rdrnd,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,tbm,vzeroupper,x87,xop,xsave,xsaveopt") }, + { str_lit("bonnell"), str_lit("64bit,64bit-mode,cmov,cx16,cx8,fast-imm16,fxsr,idivl-to-divb,idivq-to-divl,lea-sp,lea-uses-ag,mmx,movbe,no-bypass-delay,nopl,pad-short-functions,sahf,slow-two-mem-ops,slow-unaligned-mem-16,sse,sse2,sse3,ssse3,vzeroupper,x87") }, + { str_lit("broadwell"), str_lit("64bit,64bit-mode,adx,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("btver1"), str_lit("64bit,64bit-mode,cmov,cx16,cx8,fast-15bytenop,fast-imm16,fast-scalar-shift-masks,fast-vector-shift-masks,fxsr,idivq-to-divl,lzcnt,mmx,nopl,popcnt,prfchw,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4a,ssse3,vzeroupper,x87") }, + { str_lit("btver2"), str_lit("64bit,64bit-mode,aes,avx,bmi,cmov,crc32,cx16,cx8,f16c,fast-15bytenop,fast-bextr,fast-hops,fast-imm16,fast-lzcnt,fast-movbe,fast-scalar-shift-masks,fast-vector-shift-masks,fxsr,idivq-to-divl,lzcnt,mmx,movbe,nopl,pclmul,popcnt,prfchw,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,x87,xsave,xsaveopt") }, + { str_lit("c3"), str_lit("64bit-mode,mmx,prfchw,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("c3-2"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("cannonlake"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vl,bmi,bmi2,clflushopt,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdrnd,rdseed,sahf,sha,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("cascadelake"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avx512bw,avx512cd,avx512dq,avx512f,avx512vl,avx512vnni,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,faster-shift-than-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("clearwaterforest"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avxifma,avxneconvert,avxvnni,avxvnniint16,avxvnniint8,bmi,bmi2,cldemote,clflushopt,clwb,cmov,cmpccxadd,crc32,cx16,cx8,enqcmd,f16c,false-deps-perm,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-movmsk-over-vtest,prefetchi,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,sha512,shstk,slow-3ops-lea,sm3,sm4,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,uintr,usermsr,vaes,vpclmulqdq,vzeroupper,waitpkg,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("cooperlake"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avx512bf16,avx512bw,avx512cd,avx512dq,avx512f,avx512vl,avx512vnni,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,faster-shift-than-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("core-avx-i"), str_lit("64bit,64bit-mode,avx,cmov,crc32,cx16,cx8,f16c,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fsgsbase,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,rdrnd,sahf,slow-3ops-lea,slow-unaligned-mem-32,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("core-avx2"), str_lit("64bit,64bit-mode,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,rdrnd,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("core2"), str_lit("64bit,64bit-mode,cmov,cx16,cx8,fxsr,macrofusion,mmx,nopl,sahf,slow-unaligned-mem-16,sse,sse2,sse3,ssse3,vzeroupper,x87") }, + { str_lit("core_2_duo_sse4_1"), str_lit("64bit,64bit-mode,cmov,cx16,cx8,fxsr,macrofusion,mmx,nopl,sahf,slow-unaligned-mem-16,sse,sse2,sse3,sse4.1,ssse3,vzeroupper,x87") }, + { str_lit("core_2_duo_ssse3"), str_lit("64bit,64bit-mode,cmov,cx16,cx8,fxsr,macrofusion,mmx,nopl,sahf,slow-unaligned-mem-16,sse,sse2,sse3,ssse3,vzeroupper,x87") }, + { str_lit("core_2nd_gen_avx"), str_lit("64bit,64bit-mode,avx,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,sahf,slow-3ops-lea,slow-unaligned-mem-32,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("core_3rd_gen_avx"), str_lit("64bit,64bit-mode,avx,cmov,crc32,cx16,cx8,f16c,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fsgsbase,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,rdrnd,sahf,slow-3ops-lea,slow-unaligned-mem-32,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("core_4th_gen_avx"), str_lit("64bit,64bit-mode,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,rdrnd,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("core_4th_gen_avx_tsx"), str_lit("64bit,64bit-mode,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,rdrnd,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("core_5th_gen_avx"), str_lit("64bit,64bit-mode,adx,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("core_5th_gen_avx_tsx"), str_lit("64bit,64bit-mode,adx,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("core_aes_pclmulqdq"), str_lit("64bit,64bit-mode,cmov,crc32,cx16,cx8,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,sahf,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87") }, + { str_lit("core_i7_sse4_2"), str_lit("64bit,64bit-mode,cmov,crc32,cx16,cx8,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,popcnt,sahf,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87") }, + { str_lit("corei7"), str_lit("64bit,64bit-mode,cmov,crc32,cx16,cx8,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,popcnt,sahf,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87") }, + { str_lit("corei7-avx"), str_lit("64bit,64bit-mode,avx,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,sahf,slow-3ops-lea,slow-unaligned-mem-32,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("diamondrapids"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,amx-avx512,amx-bf16,amx-complex,amx-fp16,amx-fp8,amx-int8,amx-movrs,amx-tf32,amx-tile,amx-transpose,avx,avx10.1-256,avx10.1-512,avx10.2-256,avx10.2-512,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512fp16,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,avxifma,avxneconvert,avxvnni,avxvnniint16,avxvnniint8,bmi,bmi2,branch-hint,ccmp,cf,cldemote,clflushopt,clwb,cmov,cmpccxadd,crc32,cx16,cx8,egpr,enqcmd,ermsb,evex512,f16c,false-deps-getmant,false-deps-mulc,false-deps-mullq,false-deps-perm,false-deps-range,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,movrs,ndd,nf,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,ppx,prefer-256-bit,prefetchi,prfchw,ptwrite,push2pop2,rdpid,rdrnd,rdseed,sahf,serialize,sha,sha512,shstk,sm3,sm4,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tsxldtrk,tuning-fast-imm-vector-shift,uintr,usermsr,vaes,vpclmulqdq,vzeroupper,waitpkg,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves,zu") }, + { str_lit("emeraldrapids"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,amx-bf16,amx-int8,amx-tile,avx,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512fp16,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,avxvnni,bmi,bmi2,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,enqcmd,ermsb,evex512,f16c,false-deps-getmant,false-deps-mulc,false-deps-mullq,false-deps-perm,false-deps-range,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-256-bit,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tsxldtrk,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("generic"), str_lit("64bit,64bit-mode,cx8,fast-15bytenop,fast-scalar-fsqrt,idivq-to-divl,macrofusion,slow-3ops-lea,sse,sse2,vzeroupper,x87") }, + { str_lit("geode"), str_lit("64bit-mode,cx8,mmx,prfchw,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("goldmont"), str_lit("64bit,64bit-mode,aes,clflushopt,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-imm16,fast-movbe,fsgsbase,fxsr,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,rdrnd,rdseed,sahf,sha,slow-incdec,slow-lea,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-glm-div-sqrt-costs,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("goldmont-plus"), str_lit("64bit,64bit-mode,aes,clflushopt,cmov,crc32,cx16,cx8,fast-imm16,fast-movbe,fsgsbase,fxsr,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,sha,slow-incdec,slow-lea,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-glm-div-sqrt-costs,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("goldmont_plus"), str_lit("64bit,64bit-mode,aes,clflushopt,cmov,crc32,cx16,cx8,fast-imm16,fast-movbe,fsgsbase,fxsr,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,sha,slow-incdec,slow-lea,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-glm-div-sqrt-costs,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("gracemont"), str_lit("64bit,64bit-mode,adx,aes,avx,avx2,avxvnni,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,f16c,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,nopl,pclmul,pconfig,pku,popcnt,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("grandridge"), str_lit("64bit,64bit-mode,adx,aes,avx,avx2,avxifma,avxneconvert,avxvnni,avxvnniint8,bmi,bmi2,cldemote,clflushopt,clwb,cmov,cmpccxadd,crc32,cx16,cx8,enqcmd,f16c,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,nopl,pclmul,pconfig,pku,popcnt,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("graniterapids"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,amx-bf16,amx-fp16,amx-int8,amx-tile,avx,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512fp16,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,avxvnni,bmi,bmi2,branch-hint,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,enqcmd,ermsb,evex512,f16c,false-deps-getmant,false-deps-mulc,false-deps-mullq,false-deps-perm,false-deps-range,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-256-bit,prefetchi,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tsxldtrk,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("graniterapids-d"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,amx-bf16,amx-complex,amx-fp16,amx-int8,amx-tile,avx,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512fp16,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,avxvnni,bmi,bmi2,branch-hint,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,enqcmd,ermsb,evex512,f16c,false-deps-getmant,false-deps-mulc,false-deps-mullq,false-deps-perm,false-deps-range,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-256-bit,prefetchi,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tsxldtrk,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("graniterapids_d"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,amx-bf16,amx-complex,amx-fp16,amx-int8,amx-tile,avx,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512fp16,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,avxvnni,bmi,bmi2,branch-hint,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,enqcmd,ermsb,evex512,f16c,false-deps-getmant,false-deps-mulc,false-deps-mullq,false-deps-perm,false-deps-range,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-256-bit,prefetchi,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tsxldtrk,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("haswell"), str_lit("64bit,64bit-mode,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,rdrnd,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("i386"), str_lit("64bit-mode,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("i486"), str_lit("64bit-mode,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("i586"), str_lit("64bit-mode,cx8,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("i686"), str_lit("64bit-mode,cmov,cx8,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("icelake-client"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,bmi,bmi2,clflushopt,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdpid,rdrnd,rdseed,sahf,sha,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("icelake-server"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-256-bit,prfchw,rdpid,rdrnd,rdseed,sahf,sha,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("icelake_client"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,bmi,bmi2,clflushopt,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdpid,rdrnd,rdseed,sahf,sha,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("icelake_server"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-256-bit,prfchw,rdpid,rdrnd,rdseed,sahf,sha,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("ivybridge"), str_lit("64bit,64bit-mode,avx,cmov,crc32,cx16,cx8,f16c,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fsgsbase,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,rdrnd,sahf,slow-3ops-lea,slow-unaligned-mem-32,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("k6"), str_lit("64bit-mode,cx8,mmx,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("k6-2"), str_lit("64bit-mode,cx8,mmx,prfchw,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("k6-3"), str_lit("64bit-mode,cx8,mmx,prfchw,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("k8"), str_lit("64bit,64bit-mode,cmov,cx8,fast-scalar-shift-masks,fxsr,mmx,nopl,prfchw,sbb-dep-breaking,slow-shld,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("k8-sse3"), str_lit("64bit,64bit-mode,cmov,cx16,cx8,fast-scalar-shift-masks,fxsr,mmx,nopl,prfchw,sbb-dep-breaking,slow-shld,slow-unaligned-mem-16,sse,sse2,sse3,vzeroupper,x87") }, + { str_lit("knl"), str_lit("64bit,64bit-mode,adx,aes,avx,avx2,avx512cd,avx512f,bmi,bmi2,cmov,crc32,cx16,cx8,evex512,f16c,fast-gather,fast-imm16,fast-movbe,fma,fsgsbase,fxsr,idivq-to-divl,lzcnt,mmx,movbe,nopl,pclmul,popcnt,prefer-mask-registers,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,slow-incdec,slow-pmaddwd,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,x87,xsave,xsaveopt") }, + { str_lit("knm"), str_lit("64bit,64bit-mode,adx,aes,avx,avx2,avx512cd,avx512f,avx512vpopcntdq,bmi,bmi2,cmov,crc32,cx16,cx8,evex512,f16c,fast-gather,fast-imm16,fast-movbe,fma,fsgsbase,fxsr,idivq-to-divl,lzcnt,mmx,movbe,nopl,pclmul,popcnt,prefer-mask-registers,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,slow-incdec,slow-pmaddwd,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,x87,xsave,xsaveopt") }, + { str_lit("lakemont"), str_lit("64bit-mode,cx8,slow-unaligned-mem-16,sse,sse2,vzeroupper") }, + { str_lit("lunarlake"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avxifma,avxneconvert,avxvnni,avxvnniint16,avxvnniint8,bmi,bmi2,clflushopt,clwb,cmov,cmpccxadd,crc32,cx16,cx8,enqcmd,f16c,false-deps-perm,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-movmsk-over-vtest,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,sha512,shstk,slow-3ops-lea,sm3,sm4,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("meteorlake"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avxvnni,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,f16c,false-deps-perm,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-movmsk-over-vtest,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("mic_avx512"), str_lit("64bit,64bit-mode,adx,aes,avx,avx2,avx512cd,avx512f,bmi,bmi2,cmov,crc32,cx16,cx8,evex512,f16c,fast-gather,fast-imm16,fast-movbe,fma,fsgsbase,fxsr,idivq-to-divl,lzcnt,mmx,movbe,nopl,pclmul,popcnt,prefer-mask-registers,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,slow-incdec,slow-pmaddwd,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,x87,xsave,xsaveopt") }, + { str_lit("nehalem"), str_lit("64bit,64bit-mode,cmov,crc32,cx16,cx8,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,popcnt,sahf,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87") }, + { str_lit("nocona"), str_lit("64bit,64bit-mode,cmov,cx16,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,sse3,vzeroupper,x87") }, + { str_lit("opteron"), str_lit("64bit,64bit-mode,cmov,cx8,fast-scalar-shift-masks,fxsr,mmx,nopl,prfchw,sbb-dep-breaking,slow-shld,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("opteron-sse3"), str_lit("64bit,64bit-mode,cmov,cx16,cx8,fast-scalar-shift-masks,fxsr,mmx,nopl,prfchw,sbb-dep-breaking,slow-shld,slow-unaligned-mem-16,sse,sse2,sse3,vzeroupper,x87") }, + { str_lit("pantherlake"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avxifma,avxneconvert,avxvnni,avxvnniint16,avxvnniint8,bmi,bmi2,clflushopt,clwb,cmov,cmpccxadd,crc32,cx16,cx8,enqcmd,f16c,false-deps-perm,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-movmsk-over-vtest,prefetchi,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,sha512,shstk,slow-3ops-lea,sm3,sm4,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("penryn"), str_lit("64bit,64bit-mode,cmov,cx16,cx8,fxsr,macrofusion,mmx,nopl,sahf,slow-unaligned-mem-16,sse,sse2,sse3,sse4.1,ssse3,vzeroupper,x87") }, + { str_lit("pentium"), str_lit("64bit-mode,cx8,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("pentium-m"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("pentium-mmx"), str_lit("64bit-mode,cx8,mmx,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("pentium2"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("pentium3"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("pentium3m"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("pentium4"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("pentium4m"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("pentium_4"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("pentium_4_sse3"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,sse3,vzeroupper,x87") }, + { str_lit("pentium_ii"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("pentium_iii"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("pentium_iii_no_xmm_regs"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("pentium_m"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("pentium_mmx"), str_lit("64bit-mode,cx8,mmx,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("pentium_pro"), str_lit("64bit-mode,cmov,cx8,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("pentiumpro"), str_lit("64bit-mode,cmov,cx8,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("prescott"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,sse3,vzeroupper,x87") }, + { str_lit("raptorlake"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avxvnni,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,f16c,false-deps-perm,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-movmsk-over-vtest,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("rocketlake"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,bmi,bmi2,clflushopt,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdpid,rdrnd,rdseed,sahf,sha,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("sandybridge"), str_lit("64bit,64bit-mode,avx,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,sahf,slow-3ops-lea,slow-unaligned-mem-32,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("sapphirerapids"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,amx-bf16,amx-int8,amx-tile,avx,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512fp16,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,avxvnni,bmi,bmi2,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,enqcmd,ermsb,evex512,f16c,false-deps-getmant,false-deps-mulc,false-deps-mullq,false-deps-perm,false-deps-range,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-256-bit,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tsxldtrk,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("sierraforest"), str_lit("64bit,64bit-mode,adx,aes,avx,avx2,avxifma,avxneconvert,avxvnni,avxvnniint8,bmi,bmi2,cldemote,clflushopt,clwb,cmov,cmpccxadd,crc32,cx16,cx8,enqcmd,f16c,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,nopl,pclmul,pconfig,pku,popcnt,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("silvermont"), str_lit("64bit,64bit-mode,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-7bytenop,fast-imm16,fast-movbe,fxsr,idivq-to-divl,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,rdrnd,sahf,slow-incdec,slow-lea,slow-pmulld,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-slm-arith-costs,vzeroupper,x87") }, + { str_lit("skx"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avx512bw,avx512cd,avx512dq,avx512f,avx512vl,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,faster-shift-than-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("skylake"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,bmi,bmi2,clflushopt,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("skylake-avx512"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avx512bw,avx512cd,avx512dq,avx512f,avx512vl,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,faster-shift-than-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("skylake_avx512"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avx512bw,avx512cd,avx512dq,avx512f,avx512vl,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,faster-shift-than-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("slm"), str_lit("64bit,64bit-mode,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-7bytenop,fast-imm16,fast-movbe,fxsr,idivq-to-divl,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,rdrnd,sahf,slow-incdec,slow-lea,slow-pmulld,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-slm-arith-costs,vzeroupper,x87") }, + { str_lit("tigerlake"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vp2intersect,avx512vpopcntdq,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdpid,rdrnd,rdseed,sahf,sha,shstk,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("tremont"), str_lit("64bit,64bit-mode,aes,clflushopt,clwb,cmov,crc32,cx16,cx8,fast-imm16,fast-movbe,fsgsbase,fxsr,gfni,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,sha,slow-incdec,slow-lea,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-glm-div-sqrt-costs,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("westmere"), str_lit("64bit,64bit-mode,cmov,crc32,cx16,cx8,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,sahf,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87") }, + { str_lit("winchip-c6"), str_lit("64bit-mode,mmx,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("winchip2"), str_lit("64bit-mode,mmx,prfchw,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("x86-64"), str_lit("64bit,64bit-mode,cmov,cx8,fxsr,idivq-to-divl,macrofusion,mmx,nopl,slow-3ops-lea,slow-incdec,sse,sse2,vzeroupper,x87") }, + { str_lit("x86-64-v2"), str_lit("64bit,64bit-mode,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fxsr,idivq-to-divl,macrofusion,mmx,nopl,popcnt,sahf,slow-3ops-lea,slow-unaligned-mem-32,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87") }, + { str_lit("x86-64-v3"), str_lit("64bit,64bit-mode,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fxsr,idivq-to-divl,lzcnt,macrofusion,mmx,movbe,nopl,popcnt,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave") }, + { str_lit("x86-64-v4"), str_lit("64bit,64bit-mode,allow-light-256-bit,avx,avx2,avx512bw,avx512cd,avx512dq,avx512f,avx512vl,bmi,bmi2,cmov,crc32,cx16,cx8,evex512,f16c,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fxsr,idivq-to-divl,lzcnt,macrofusion,mmx,movbe,nopl,popcnt,prefer-256-bit,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave") }, + { str_lit("yonah"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,sse3,vzeroupper,x87") }, + { str_lit("znver1"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,bmi,bmi2,branchfusion,clflushopt,clzero,cmov,crc32,cx16,cx8,f16c,fast-15bytenop,fast-bextr,fast-imm16,fast-lzcnt,fast-movbe,fast-scalar-fsqrt,fast-scalar-shift-masks,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,idivq-to-divl,lzcnt,mmx,movbe,mwaitx,nopl,pclmul,popcnt,prfchw,rdrnd,rdseed,sahf,sbb-dep-breaking,sha,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("znver2"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,bmi,bmi2,branchfusion,clflushopt,clwb,clzero,cmov,crc32,cx16,cx8,f16c,fast-15bytenop,fast-bextr,fast-imm16,fast-lzcnt,fast-movbe,fast-scalar-fsqrt,fast-scalar-shift-masks,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,idivq-to-divl,lzcnt,mmx,movbe,mwaitx,nopl,pclmul,popcnt,prfchw,rdpid,rdpru,rdrnd,rdseed,sahf,sbb-dep-breaking,sha,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,vzeroupper,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("znver3"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,bmi,bmi2,branchfusion,clflushopt,clwb,clzero,cmov,crc32,cx16,cx8,f16c,fast-15bytenop,fast-bextr,fast-imm16,fast-lzcnt,fast-movbe,fast-scalar-fsqrt,fast-scalar-shift-masks,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,mwaitx,nopl,pclmul,pku,popcnt,prfchw,rdpid,rdpru,rdrnd,rdseed,sahf,sbb-dep-breaking,sha,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,vaes,vpclmulqdq,vzeroupper,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("znver4"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,bmi,bmi2,branchfusion,clflushopt,clwb,clzero,cmov,crc32,cx16,cx8,evex512,f16c,fast-15bytenop,fast-bextr,fast-dpwssd,fast-imm16,fast-lzcnt,fast-movbe,fast-scalar-fsqrt,fast-scalar-shift-masks,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,mwaitx,nopl,pclmul,pku,popcnt,prfchw,rdpid,rdpru,rdrnd,rdseed,sahf,sbb-dep-breaking,sha,shstk,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,vaes,vpclmulqdq,vzeroupper,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("znver5"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vp2intersect,avx512vpopcntdq,avxvnni,bmi,bmi2,branchfusion,clflushopt,clwb,clzero,cmov,crc32,cx16,cx8,evex512,f16c,fast-15bytenop,fast-bextr,fast-dpwssd,fast-imm16,fast-lzcnt,fast-movbe,fast-scalar-fsqrt,fast-scalar-shift-masks,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,mwaitx,nopl,pclmul,pku,popcnt,prefetchi,prfchw,rdpid,rdpru,rdrnd,rdseed,sahf,sbb-dep-breaking,sha,shstk,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,vaes,vpclmulqdq,vzeroupper,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, + // TargetArch_i386: + { str_lit("alderlake"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avxvnni,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,f16c,false-deps-perm,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-movmsk-over-vtest,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("amdfam10"), str_lit("32bit-mode,64bit,cmov,cx16,cx8,fast-scalar-shift-masks,fxsr,idivq-to-divl,lzcnt,nopl,popcnt,prfchw,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4a,vzeroupper,x87") }, + { str_lit("arrowlake"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avxifma,avxneconvert,avxvnni,avxvnniint8,bmi,bmi2,clflushopt,clwb,cmov,cmpccxadd,crc32,cx16,cx8,enqcmd,f16c,false-deps-perm,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-movmsk-over-vtest,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("arrowlake-s"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avxifma,avxneconvert,avxvnni,avxvnniint16,avxvnniint8,bmi,bmi2,clflushopt,clwb,cmov,cmpccxadd,crc32,cx16,cx8,enqcmd,f16c,false-deps-perm,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-movmsk-over-vtest,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,sha512,shstk,slow-3ops-lea,sm3,sm4,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("arrowlake_s"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avxifma,avxneconvert,avxvnni,avxvnniint16,avxvnniint8,bmi,bmi2,clflushopt,clwb,cmov,cmpccxadd,crc32,cx16,cx8,enqcmd,f16c,false-deps-perm,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-movmsk-over-vtest,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,sha512,shstk,slow-3ops-lea,sm3,sm4,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("athlon"), str_lit("32bit-mode,cmov,cx8,mmx,nopl,prfchw,slow-shld,slow-unaligned-mem-16,vzeroupper,x87") }, + { str_lit("athlon-4"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,prfchw,slow-shld,slow-unaligned-mem-16,sse,vzeroupper,x87") }, + { str_lit("athlon-fx"), str_lit("32bit-mode,64bit,cmov,cx8,fast-scalar-shift-masks,fxsr,mmx,nopl,prfchw,sbb-dep-breaking,slow-shld,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("athlon-mp"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,prfchw,slow-shld,slow-unaligned-mem-16,sse,vzeroupper,x87") }, + { str_lit("athlon-tbird"), str_lit("32bit-mode,cmov,cx8,mmx,nopl,prfchw,slow-shld,slow-unaligned-mem-16,vzeroupper,x87") }, + { str_lit("athlon-xp"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,prfchw,slow-shld,slow-unaligned-mem-16,sse,vzeroupper,x87") }, + { str_lit("athlon64"), str_lit("32bit-mode,64bit,cmov,cx8,fast-scalar-shift-masks,fxsr,mmx,nopl,prfchw,sbb-dep-breaking,slow-shld,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("athlon64-sse3"), str_lit("32bit-mode,64bit,cmov,cx16,cx8,fast-scalar-shift-masks,fxsr,mmx,nopl,prfchw,sbb-dep-breaking,slow-shld,slow-unaligned-mem-16,sse,sse2,sse3,vzeroupper,x87") }, + { str_lit("atom"), str_lit("32bit-mode,64bit,cmov,cx16,cx8,fast-imm16,fxsr,idivl-to-divb,idivq-to-divl,lea-sp,lea-uses-ag,mmx,movbe,no-bypass-delay,nopl,pad-short-functions,sahf,slow-two-mem-ops,slow-unaligned-mem-16,sse,sse2,sse3,ssse3,vzeroupper,x87") }, + { str_lit("atom_sse4_2"), str_lit("32bit-mode,64bit,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-7bytenop,fast-imm16,fast-movbe,fxsr,idivq-to-divl,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,rdrnd,sahf,slow-incdec,slow-lea,slow-pmulld,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-slm-arith-costs,vzeroupper,x87") }, + { str_lit("atom_sse4_2_movbe"), str_lit("32bit-mode,64bit,aes,clflushopt,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-7bytenop,fast-imm16,fast-movbe,fsgsbase,fxsr,idivq-to-divl,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,rdrnd,rdseed,sahf,sha,slow-incdec,slow-lea,slow-pmulld,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-slm-arith-costs,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("barcelona"), str_lit("32bit-mode,64bit,cmov,cx16,cx8,fast-scalar-shift-masks,fxsr,idivq-to-divl,lzcnt,nopl,popcnt,prfchw,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4a,vzeroupper,x87") }, + { str_lit("bdver1"), str_lit("32bit-mode,64bit,aes,avx,branchfusion,cmov,crc32,cx16,cx8,fast-11bytenop,fast-scalar-shift-masks,fma4,fxsr,idivq-to-divl,lwp,lzcnt,mmx,nopl,pclmul,popcnt,prfchw,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,vzeroupper,x87,xop,xsave") }, + { str_lit("bdver2"), str_lit("32bit-mode,64bit,aes,avx,bmi,branchfusion,cmov,crc32,cx16,cx8,f16c,fast-11bytenop,fast-bextr,fast-movbe,fast-scalar-shift-masks,fma,fma4,fxsr,idivq-to-divl,lwp,lzcnt,mmx,nopl,pclmul,popcnt,prfchw,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,tbm,vzeroupper,x87,xop,xsave") }, + { str_lit("bdver3"), str_lit("32bit-mode,64bit,aes,avx,bmi,branchfusion,cmov,crc32,cx16,cx8,f16c,fast-11bytenop,fast-bextr,fast-movbe,fast-scalar-shift-masks,fma,fma4,fsgsbase,fxsr,idivq-to-divl,lwp,lzcnt,mmx,nopl,pclmul,popcnt,prfchw,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,tbm,vzeroupper,x87,xop,xsave,xsaveopt") }, + { str_lit("bdver4"), str_lit("32bit-mode,64bit,aes,avx,avx2,bmi,bmi2,branchfusion,cmov,crc32,cx16,cx8,f16c,fast-11bytenop,fast-bextr,fast-movbe,fast-scalar-shift-masks,fma,fma4,fsgsbase,fxsr,idivq-to-divl,lwp,lzcnt,mmx,movbe,mwaitx,nopl,pclmul,popcnt,prfchw,rdrnd,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,tbm,vzeroupper,x87,xop,xsave,xsaveopt") }, + { str_lit("bonnell"), str_lit("32bit-mode,64bit,cmov,cx16,cx8,fast-imm16,fxsr,idivl-to-divb,idivq-to-divl,lea-sp,lea-uses-ag,mmx,movbe,no-bypass-delay,nopl,pad-short-functions,sahf,slow-two-mem-ops,slow-unaligned-mem-16,sse,sse2,sse3,ssse3,vzeroupper,x87") }, + { str_lit("broadwell"), str_lit("32bit-mode,64bit,adx,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("btver1"), str_lit("32bit-mode,64bit,cmov,cx16,cx8,fast-15bytenop,fast-imm16,fast-scalar-shift-masks,fast-vector-shift-masks,fxsr,idivq-to-divl,lzcnt,mmx,nopl,popcnt,prfchw,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4a,ssse3,vzeroupper,x87") }, + { str_lit("btver2"), str_lit("32bit-mode,64bit,aes,avx,bmi,cmov,crc32,cx16,cx8,f16c,fast-15bytenop,fast-bextr,fast-hops,fast-imm16,fast-lzcnt,fast-movbe,fast-scalar-shift-masks,fast-vector-shift-masks,fxsr,idivq-to-divl,lzcnt,mmx,movbe,nopl,pclmul,popcnt,prfchw,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,x87,xsave,xsaveopt") }, + { str_lit("c3"), str_lit("32bit-mode,mmx,prfchw,slow-unaligned-mem-16,vzeroupper,x87") }, + { str_lit("c3-2"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,slow-unaligned-mem-16,sse,vzeroupper,x87") }, + { str_lit("cannonlake"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vl,bmi,bmi2,clflushopt,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdrnd,rdseed,sahf,sha,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("cascadelake"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avx512bw,avx512cd,avx512dq,avx512f,avx512vl,avx512vnni,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,faster-shift-than-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("clearwaterforest"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avxifma,avxneconvert,avxvnni,avxvnniint16,avxvnniint8,bmi,bmi2,cldemote,clflushopt,clwb,cmov,cmpccxadd,crc32,cx16,cx8,enqcmd,f16c,false-deps-perm,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-movmsk-over-vtest,prefetchi,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,sha512,shstk,slow-3ops-lea,sm3,sm4,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,uintr,usermsr,vaes,vpclmulqdq,vzeroupper,waitpkg,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("cooperlake"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avx512bf16,avx512bw,avx512cd,avx512dq,avx512f,avx512vl,avx512vnni,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,faster-shift-than-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("core-avx-i"), str_lit("32bit-mode,64bit,avx,cmov,crc32,cx16,cx8,f16c,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fsgsbase,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,rdrnd,sahf,slow-3ops-lea,slow-unaligned-mem-32,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("core-avx2"), str_lit("32bit-mode,64bit,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,rdrnd,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("core2"), str_lit("32bit-mode,64bit,cmov,cx16,cx8,fxsr,macrofusion,mmx,nopl,sahf,slow-unaligned-mem-16,sse,sse2,sse3,ssse3,vzeroupper,x87") }, + { str_lit("core_2_duo_sse4_1"), str_lit("32bit-mode,64bit,cmov,cx16,cx8,fxsr,macrofusion,mmx,nopl,sahf,slow-unaligned-mem-16,sse,sse2,sse3,sse4.1,ssse3,vzeroupper,x87") }, + { str_lit("core_2_duo_ssse3"), str_lit("32bit-mode,64bit,cmov,cx16,cx8,fxsr,macrofusion,mmx,nopl,sahf,slow-unaligned-mem-16,sse,sse2,sse3,ssse3,vzeroupper,x87") }, + { str_lit("core_2nd_gen_avx"), str_lit("32bit-mode,64bit,avx,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,sahf,slow-3ops-lea,slow-unaligned-mem-32,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("core_3rd_gen_avx"), str_lit("32bit-mode,64bit,avx,cmov,crc32,cx16,cx8,f16c,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fsgsbase,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,rdrnd,sahf,slow-3ops-lea,slow-unaligned-mem-32,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("core_4th_gen_avx"), str_lit("32bit-mode,64bit,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,rdrnd,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("core_4th_gen_avx_tsx"), str_lit("32bit-mode,64bit,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,rdrnd,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("core_5th_gen_avx"), str_lit("32bit-mode,64bit,adx,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("core_5th_gen_avx_tsx"), str_lit("32bit-mode,64bit,adx,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("core_aes_pclmulqdq"), str_lit("32bit-mode,64bit,cmov,crc32,cx16,cx8,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,sahf,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87") }, + { str_lit("core_i7_sse4_2"), str_lit("32bit-mode,64bit,cmov,crc32,cx16,cx8,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,popcnt,sahf,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87") }, + { str_lit("corei7"), str_lit("32bit-mode,64bit,cmov,crc32,cx16,cx8,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,popcnt,sahf,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87") }, + { str_lit("corei7-avx"), str_lit("32bit-mode,64bit,avx,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,sahf,slow-3ops-lea,slow-unaligned-mem-32,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("diamondrapids"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,amx-avx512,amx-bf16,amx-complex,amx-fp16,amx-fp8,amx-int8,amx-movrs,amx-tf32,amx-tile,amx-transpose,avx,avx10.1-256,avx10.1-512,avx10.2-256,avx10.2-512,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512fp16,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,avxifma,avxneconvert,avxvnni,avxvnniint16,avxvnniint8,bmi,bmi2,branch-hint,ccmp,cf,cldemote,clflushopt,clwb,cmov,cmpccxadd,crc32,cx16,cx8,egpr,enqcmd,ermsb,evex512,f16c,false-deps-getmant,false-deps-mulc,false-deps-mullq,false-deps-perm,false-deps-range,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,movrs,ndd,nf,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,ppx,prefer-256-bit,prefetchi,prfchw,ptwrite,push2pop2,rdpid,rdrnd,rdseed,sahf,serialize,sha,sha512,shstk,sm3,sm4,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tsxldtrk,tuning-fast-imm-vector-shift,uintr,usermsr,vaes,vpclmulqdq,vzeroupper,waitpkg,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves,zu") }, + { str_lit("emeraldrapids"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,amx-bf16,amx-int8,amx-tile,avx,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512fp16,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,avxvnni,bmi,bmi2,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,enqcmd,ermsb,evex512,f16c,false-deps-getmant,false-deps-mulc,false-deps-mullq,false-deps-perm,false-deps-range,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-256-bit,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tsxldtrk,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("generic"), str_lit("32bit-mode,64bit,cx8,fast-15bytenop,fast-scalar-fsqrt,idivq-to-divl,macrofusion,slow-3ops-lea,vzeroupper,x87") }, + { str_lit("geode"), str_lit("32bit-mode,cx8,mmx,prfchw,slow-unaligned-mem-16,vzeroupper,x87") }, + { str_lit("goldmont"), str_lit("32bit-mode,64bit,aes,clflushopt,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-imm16,fast-movbe,fsgsbase,fxsr,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,rdrnd,rdseed,sahf,sha,slow-incdec,slow-lea,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-glm-div-sqrt-costs,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("goldmont-plus"), str_lit("32bit-mode,64bit,aes,clflushopt,cmov,crc32,cx16,cx8,fast-imm16,fast-movbe,fsgsbase,fxsr,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,sha,slow-incdec,slow-lea,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-glm-div-sqrt-costs,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("goldmont_plus"), str_lit("32bit-mode,64bit,aes,clflushopt,cmov,crc32,cx16,cx8,fast-imm16,fast-movbe,fsgsbase,fxsr,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,sha,slow-incdec,slow-lea,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-glm-div-sqrt-costs,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("gracemont"), str_lit("32bit-mode,64bit,adx,aes,avx,avx2,avxvnni,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,f16c,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,nopl,pclmul,pconfig,pku,popcnt,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("grandridge"), str_lit("32bit-mode,64bit,adx,aes,avx,avx2,avxifma,avxneconvert,avxvnni,avxvnniint8,bmi,bmi2,cldemote,clflushopt,clwb,cmov,cmpccxadd,crc32,cx16,cx8,enqcmd,f16c,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,nopl,pclmul,pconfig,pku,popcnt,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("graniterapids"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,amx-bf16,amx-fp16,amx-int8,amx-tile,avx,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512fp16,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,avxvnni,bmi,bmi2,branch-hint,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,enqcmd,ermsb,evex512,f16c,false-deps-getmant,false-deps-mulc,false-deps-mullq,false-deps-perm,false-deps-range,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-256-bit,prefetchi,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tsxldtrk,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("graniterapids-d"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,amx-bf16,amx-complex,amx-fp16,amx-int8,amx-tile,avx,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512fp16,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,avxvnni,bmi,bmi2,branch-hint,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,enqcmd,ermsb,evex512,f16c,false-deps-getmant,false-deps-mulc,false-deps-mullq,false-deps-perm,false-deps-range,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-256-bit,prefetchi,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tsxldtrk,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("graniterapids_d"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,amx-bf16,amx-complex,amx-fp16,amx-int8,amx-tile,avx,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512fp16,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,avxvnni,bmi,bmi2,branch-hint,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,enqcmd,ermsb,evex512,f16c,false-deps-getmant,false-deps-mulc,false-deps-mullq,false-deps-perm,false-deps-range,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-256-bit,prefetchi,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tsxldtrk,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("haswell"), str_lit("32bit-mode,64bit,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,rdrnd,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("i386"), str_lit("32bit-mode,slow-unaligned-mem-16,vzeroupper,x87") }, + { str_lit("i486"), str_lit("32bit-mode,slow-unaligned-mem-16,vzeroupper,x87") }, + { str_lit("i586"), str_lit("32bit-mode,cx8,slow-unaligned-mem-16,vzeroupper,x87") }, + { str_lit("i686"), str_lit("32bit-mode,cmov,cx8,slow-unaligned-mem-16,vzeroupper,x87") }, + { str_lit("icelake-client"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,bmi,bmi2,clflushopt,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdpid,rdrnd,rdseed,sahf,sha,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("icelake-server"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-256-bit,prfchw,rdpid,rdrnd,rdseed,sahf,sha,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("icelake_client"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,bmi,bmi2,clflushopt,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdpid,rdrnd,rdseed,sahf,sha,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("icelake_server"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-256-bit,prfchw,rdpid,rdrnd,rdseed,sahf,sha,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("ivybridge"), str_lit("32bit-mode,64bit,avx,cmov,crc32,cx16,cx8,f16c,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fsgsbase,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,rdrnd,sahf,slow-3ops-lea,slow-unaligned-mem-32,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("k6"), str_lit("32bit-mode,cx8,mmx,slow-unaligned-mem-16,vzeroupper,x87") }, + { str_lit("k6-2"), str_lit("32bit-mode,cx8,mmx,prfchw,slow-unaligned-mem-16,vzeroupper,x87") }, + { str_lit("k6-3"), str_lit("32bit-mode,cx8,mmx,prfchw,slow-unaligned-mem-16,vzeroupper,x87") }, + { str_lit("k8"), str_lit("32bit-mode,64bit,cmov,cx8,fast-scalar-shift-masks,fxsr,mmx,nopl,prfchw,sbb-dep-breaking,slow-shld,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("k8-sse3"), str_lit("32bit-mode,64bit,cmov,cx16,cx8,fast-scalar-shift-masks,fxsr,mmx,nopl,prfchw,sbb-dep-breaking,slow-shld,slow-unaligned-mem-16,sse,sse2,sse3,vzeroupper,x87") }, + { str_lit("knl"), str_lit("32bit-mode,64bit,adx,aes,avx,avx2,avx512cd,avx512f,bmi,bmi2,cmov,crc32,cx16,cx8,evex512,f16c,fast-gather,fast-imm16,fast-movbe,fma,fsgsbase,fxsr,idivq-to-divl,lzcnt,mmx,movbe,nopl,pclmul,popcnt,prefer-mask-registers,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,slow-incdec,slow-pmaddwd,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,x87,xsave,xsaveopt") }, + { str_lit("knm"), str_lit("32bit-mode,64bit,adx,aes,avx,avx2,avx512cd,avx512f,avx512vpopcntdq,bmi,bmi2,cmov,crc32,cx16,cx8,evex512,f16c,fast-gather,fast-imm16,fast-movbe,fma,fsgsbase,fxsr,idivq-to-divl,lzcnt,mmx,movbe,nopl,pclmul,popcnt,prefer-mask-registers,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,slow-incdec,slow-pmaddwd,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,x87,xsave,xsaveopt") }, + { str_lit("lakemont"), str_lit("32bit-mode,cx8,slow-unaligned-mem-16,vzeroupper") }, + { str_lit("lunarlake"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avxifma,avxneconvert,avxvnni,avxvnniint16,avxvnniint8,bmi,bmi2,clflushopt,clwb,cmov,cmpccxadd,crc32,cx16,cx8,enqcmd,f16c,false-deps-perm,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-movmsk-over-vtest,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,sha512,shstk,slow-3ops-lea,sm3,sm4,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("meteorlake"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avxvnni,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,f16c,false-deps-perm,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-movmsk-over-vtest,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("mic_avx512"), str_lit("32bit-mode,64bit,adx,aes,avx,avx2,avx512cd,avx512f,bmi,bmi2,cmov,crc32,cx16,cx8,evex512,f16c,fast-gather,fast-imm16,fast-movbe,fma,fsgsbase,fxsr,idivq-to-divl,lzcnt,mmx,movbe,nopl,pclmul,popcnt,prefer-mask-registers,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,slow-incdec,slow-pmaddwd,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,x87,xsave,xsaveopt") }, + { str_lit("nehalem"), str_lit("32bit-mode,64bit,cmov,crc32,cx16,cx8,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,popcnt,sahf,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87") }, + { str_lit("nocona"), str_lit("32bit-mode,64bit,cmov,cx16,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,sse3,vzeroupper,x87") }, + { str_lit("opteron"), str_lit("32bit-mode,64bit,cmov,cx8,fast-scalar-shift-masks,fxsr,mmx,nopl,prfchw,sbb-dep-breaking,slow-shld,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("opteron-sse3"), str_lit("32bit-mode,64bit,cmov,cx16,cx8,fast-scalar-shift-masks,fxsr,mmx,nopl,prfchw,sbb-dep-breaking,slow-shld,slow-unaligned-mem-16,sse,sse2,sse3,vzeroupper,x87") }, + { str_lit("pantherlake"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avxifma,avxneconvert,avxvnni,avxvnniint16,avxvnniint8,bmi,bmi2,clflushopt,clwb,cmov,cmpccxadd,crc32,cx16,cx8,enqcmd,f16c,false-deps-perm,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-movmsk-over-vtest,prefetchi,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,sha512,shstk,slow-3ops-lea,sm3,sm4,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("penryn"), str_lit("32bit-mode,64bit,cmov,cx16,cx8,fxsr,macrofusion,mmx,nopl,sahf,slow-unaligned-mem-16,sse,sse2,sse3,sse4.1,ssse3,vzeroupper,x87") }, + { str_lit("pentium"), str_lit("32bit-mode,cx8,slow-unaligned-mem-16,vzeroupper,x87") }, + { str_lit("pentium-m"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("pentium-mmx"), str_lit("32bit-mode,cx8,mmx,slow-unaligned-mem-16,vzeroupper,x87") }, + { str_lit("pentium2"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,vzeroupper,x87") }, + { str_lit("pentium3"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,vzeroupper,x87") }, + { str_lit("pentium3m"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,vzeroupper,x87") }, + { str_lit("pentium4"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("pentium4m"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("pentium_4"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("pentium_4_sse3"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,sse3,vzeroupper,x87") }, + { str_lit("pentium_ii"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,vzeroupper,x87") }, + { str_lit("pentium_iii"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,vzeroupper,x87") }, + { str_lit("pentium_iii_no_xmm_regs"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,vzeroupper,x87") }, + { str_lit("pentium_m"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("pentium_mmx"), str_lit("32bit-mode,cx8,mmx,slow-unaligned-mem-16,vzeroupper,x87") }, + { str_lit("pentium_pro"), str_lit("32bit-mode,cmov,cx8,nopl,slow-unaligned-mem-16,vzeroupper,x87") }, + { str_lit("pentiumpro"), str_lit("32bit-mode,cmov,cx8,nopl,slow-unaligned-mem-16,vzeroupper,x87") }, + { str_lit("prescott"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,sse3,vzeroupper,x87") }, + { str_lit("raptorlake"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avxvnni,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,f16c,false-deps-perm,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-movmsk-over-vtest,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("rocketlake"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,bmi,bmi2,clflushopt,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdpid,rdrnd,rdseed,sahf,sha,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("sandybridge"), str_lit("32bit-mode,64bit,avx,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,sahf,slow-3ops-lea,slow-unaligned-mem-32,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("sapphirerapids"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,amx-bf16,amx-int8,amx-tile,avx,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512fp16,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,avxvnni,bmi,bmi2,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,enqcmd,ermsb,evex512,f16c,false-deps-getmant,false-deps-mulc,false-deps-mullq,false-deps-perm,false-deps-range,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-256-bit,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tsxldtrk,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("sierraforest"), str_lit("32bit-mode,64bit,adx,aes,avx,avx2,avxifma,avxneconvert,avxvnni,avxvnniint8,bmi,bmi2,cldemote,clflushopt,clwb,cmov,cmpccxadd,crc32,cx16,cx8,enqcmd,f16c,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,nopl,pclmul,pconfig,pku,popcnt,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("silvermont"), str_lit("32bit-mode,64bit,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-7bytenop,fast-imm16,fast-movbe,fxsr,idivq-to-divl,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,rdrnd,sahf,slow-incdec,slow-lea,slow-pmulld,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-slm-arith-costs,vzeroupper,x87") }, + { str_lit("skx"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avx512bw,avx512cd,avx512dq,avx512f,avx512vl,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,faster-shift-than-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("skylake"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,bmi,bmi2,clflushopt,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("skylake-avx512"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avx512bw,avx512cd,avx512dq,avx512f,avx512vl,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,faster-shift-than-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("skylake_avx512"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avx512bw,avx512cd,avx512dq,avx512f,avx512vl,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,faster-shift-than-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("slm"), str_lit("32bit-mode,64bit,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-7bytenop,fast-imm16,fast-movbe,fxsr,idivq-to-divl,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,rdrnd,sahf,slow-incdec,slow-lea,slow-pmulld,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-slm-arith-costs,vzeroupper,x87") }, + { str_lit("tigerlake"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vp2intersect,avx512vpopcntdq,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdpid,rdrnd,rdseed,sahf,sha,shstk,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("tremont"), str_lit("32bit-mode,64bit,aes,clflushopt,clwb,cmov,crc32,cx16,cx8,fast-imm16,fast-movbe,fsgsbase,fxsr,gfni,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,sha,slow-incdec,slow-lea,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-glm-div-sqrt-costs,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("westmere"), str_lit("32bit-mode,64bit,cmov,crc32,cx16,cx8,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,sahf,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87") }, + { str_lit("winchip-c6"), str_lit("32bit-mode,mmx,slow-unaligned-mem-16,vzeroupper,x87") }, + { str_lit("winchip2"), str_lit("32bit-mode,mmx,prfchw,slow-unaligned-mem-16,vzeroupper,x87") }, + { str_lit("x86-64"), str_lit("32bit-mode,64bit,cmov,cx8,fxsr,idivq-to-divl,macrofusion,mmx,nopl,slow-3ops-lea,slow-incdec,sse,sse2,vzeroupper,x87") }, + { str_lit("x86-64-v2"), str_lit("32bit-mode,64bit,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fxsr,idivq-to-divl,macrofusion,mmx,nopl,popcnt,sahf,slow-3ops-lea,slow-unaligned-mem-32,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87") }, + { str_lit("x86-64-v3"), str_lit("32bit-mode,64bit,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fxsr,idivq-to-divl,lzcnt,macrofusion,mmx,movbe,nopl,popcnt,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave") }, + { str_lit("x86-64-v4"), str_lit("32bit-mode,64bit,allow-light-256-bit,avx,avx2,avx512bw,avx512cd,avx512dq,avx512f,avx512vl,bmi,bmi2,cmov,crc32,cx16,cx8,evex512,f16c,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fxsr,idivq-to-divl,lzcnt,macrofusion,mmx,movbe,nopl,popcnt,prefer-256-bit,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave") }, + { str_lit("yonah"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,sse3,vzeroupper,x87") }, + { str_lit("znver1"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,bmi,bmi2,branchfusion,clflushopt,clzero,cmov,crc32,cx16,cx8,f16c,fast-15bytenop,fast-bextr,fast-imm16,fast-lzcnt,fast-movbe,fast-scalar-fsqrt,fast-scalar-shift-masks,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,idivq-to-divl,lzcnt,mmx,movbe,mwaitx,nopl,pclmul,popcnt,prfchw,rdrnd,rdseed,sahf,sbb-dep-breaking,sha,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("znver2"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,bmi,bmi2,branchfusion,clflushopt,clwb,clzero,cmov,crc32,cx16,cx8,f16c,fast-15bytenop,fast-bextr,fast-imm16,fast-lzcnt,fast-movbe,fast-scalar-fsqrt,fast-scalar-shift-masks,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,idivq-to-divl,lzcnt,mmx,movbe,mwaitx,nopl,pclmul,popcnt,prfchw,rdpid,rdpru,rdrnd,rdseed,sahf,sbb-dep-breaking,sha,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,vzeroupper,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("znver3"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,bmi,bmi2,branchfusion,clflushopt,clwb,clzero,cmov,crc32,cx16,cx8,f16c,fast-15bytenop,fast-bextr,fast-imm16,fast-lzcnt,fast-movbe,fast-scalar-fsqrt,fast-scalar-shift-masks,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,mwaitx,nopl,pclmul,pku,popcnt,prfchw,rdpid,rdpru,rdrnd,rdseed,sahf,sbb-dep-breaking,sha,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,vaes,vpclmulqdq,vzeroupper,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("znver4"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,bmi,bmi2,branchfusion,clflushopt,clwb,clzero,cmov,crc32,cx16,cx8,evex512,f16c,fast-15bytenop,fast-bextr,fast-dpwssd,fast-imm16,fast-lzcnt,fast-movbe,fast-scalar-fsqrt,fast-scalar-shift-masks,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,mwaitx,nopl,pclmul,pku,popcnt,prfchw,rdpid,rdpru,rdrnd,rdseed,sahf,sbb-dep-breaking,sha,shstk,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,vaes,vpclmulqdq,vzeroupper,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("znver5"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vp2intersect,avx512vpopcntdq,avxvnni,bmi,bmi2,branchfusion,clflushopt,clwb,clzero,cmov,crc32,cx16,cx8,evex512,f16c,fast-15bytenop,fast-bextr,fast-dpwssd,fast-imm16,fast-lzcnt,fast-movbe,fast-scalar-fsqrt,fast-scalar-shift-masks,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,mwaitx,nopl,pclmul,pku,popcnt,prefetchi,prfchw,rdpid,rdpru,rdrnd,rdseed,sahf,sbb-dep-breaking,sha,shstk,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,vaes,vpclmulqdq,vzeroupper,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, + // TargetArch_arm32: + { str_lit("arm1020e"), str_lit("armv5te,v4t,v5t,v5te") }, + { str_lit("arm1020t"), str_lit("armv5t,v4t,v5t") }, + { str_lit("arm1022e"), str_lit("armv5te,v4t,v5t,v5te") }, + { str_lit("arm10e"), str_lit("armv5te,v4t,v5t,v5te") }, + { str_lit("arm10tdmi"), str_lit("armv5t,v4t,v5t") }, + { str_lit("arm1136j-s"), str_lit("armv6,dsp,v4t,v5t,v5te,v6") }, + { str_lit("arm1136jf-s"), str_lit("armv6,dsp,fp64,fpregs,fpregs64,slowfpvmlx,v4t,v5t,v5te,v6,vfp2,vfp2sp") }, + { str_lit("arm1156t2-s"), str_lit("armv6t2,dsp,thumb2,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v8m") }, + { str_lit("arm1156t2f-s"), str_lit("armv6t2,dsp,fp64,fpregs,fpregs64,slowfpvmlx,thumb2,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v8m,vfp2,vfp2sp") }, + { str_lit("arm1176jz-s"), str_lit("armv6kz,trustzone,v4t,v5t,v5te,v6,v6k") }, + { str_lit("arm1176jzf-s"), str_lit("armv6kz,fp64,fpregs,fpregs64,slowfpvmlx,trustzone,v4t,v5t,v5te,v6,v6k,vfp2,vfp2sp") }, + { str_lit("arm710t"), str_lit("armv4t,v4t") }, + { str_lit("arm720t"), str_lit("armv4t,v4t") }, + { str_lit("arm7tdmi"), str_lit("armv4t,v4t") }, + { str_lit("arm7tdmi-s"), str_lit("armv4t,v4t") }, + { str_lit("arm8"), str_lit("armv4") }, + { str_lit("arm810"), str_lit("armv4") }, + { str_lit("arm9"), str_lit("armv4t,v4t") }, + { str_lit("arm920"), str_lit("armv4t,v4t") }, + { str_lit("arm920t"), str_lit("armv4t,v4t") }, + { str_lit("arm922t"), str_lit("armv4t,v4t") }, + { str_lit("arm926ej-s"), str_lit("armv5te,v4t,v5t,v5te") }, + { str_lit("arm940t"), str_lit("armv4t,v4t") }, + { str_lit("arm946e-s"), str_lit("armv5te,v4t,v5t,v5te") }, + { str_lit("arm966e-s"), str_lit("armv5te,v4t,v5t,v5te") }, + { str_lit("arm968e-s"), str_lit("armv5te,v4t,v5t,v5te") }, + { str_lit("arm9e"), str_lit("armv5te,v4t,v5t,v5te") }, + { str_lit("arm9tdmi"), str_lit("armv4t,v4t") }, + { str_lit("cortex-a12"), str_lit("a12,aclass,armv7-a,avoid-partial-cpsr,d32,db,dsp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,perfmon,ret-addr-stack,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization,vmlx-forwarding") }, + { str_lit("cortex-a15"), str_lit("a15,aclass,armv7-a,avoid-partial-cpsr,d32,db,dont-widen-vmovs,dsp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,muxed-units,perfmon,ret-addr-stack,splat-vfp-neon,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization,vldn-align") }, + { str_lit("cortex-a17"), str_lit("a17,aclass,armv7-a,avoid-partial-cpsr,d32,db,dsp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,perfmon,ret-addr-stack,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization,vmlx-forwarding") }, + { str_lit("cortex-a32"), str_lit("aclass,acquire-release,aes,armv8-a,crc,crypto,d32,db,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,perfmon,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("cortex-a35"), str_lit("a35,aclass,acquire-release,aes,armv8-a,crc,crypto,d32,db,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,perfmon,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("cortex-a5"), str_lit("a5,aclass,armv7-a,d32,db,dsp,fp16,fp64,fpregs,fpregs64,mp,perfmon,ret-addr-stack,slow-fp-brcc,slowfpvfmx,slowfpvmlx,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,vmlx-forwarding") }, + { str_lit("cortex-a510"), str_lit("aclass,acquire-release,armv9-a,bf16,cortex-a710,crc,d32,db,dotprod,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp16fml,fp64,fpregs,fpregs16,fpregs64,fullfp16,hwdiv,hwdiv-arm,i8mm,mp,neon,perfmon,ras,sb,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8m,v9a,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("cortex-a53"), str_lit("a53,aclass,acquire-release,aes,armv8-a,crc,crypto,d32,db,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpao,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,perfmon,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("cortex-a55"), str_lit("a55,aclass,acquire-release,aes,armv8.2-a,crc,crypto,d32,db,dotprod,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,perfmon,ras,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("cortex-a57"), str_lit("a57,aclass,acquire-release,aes,armv8-a,avoid-partial-cpsr,cheap-predicable-cpsr,crc,crypto,d32,db,dsp,fix-cortex-a57-aes-1742098,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpao,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,perfmon,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("cortex-a7"), str_lit("a7,aclass,armv7-a,d32,db,dsp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,perfmon,ret-addr-stack,slow-fp-brcc,slowfpvfmx,slowfpvmlx,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization,vmlx-forwarding,vmlx-hazards") }, + { str_lit("cortex-a710"), str_lit("aclass,acquire-release,armv9-a,bf16,cortex-a710,crc,d32,db,dotprod,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp16fml,fp64,fpregs,fpregs16,fpregs64,fullfp16,hwdiv,hwdiv-arm,i8mm,mp,neon,perfmon,ras,sb,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8m,v9a,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("cortex-a72"), str_lit("a72,aclass,acquire-release,aes,armv8-a,crc,crypto,d32,db,dsp,fix-cortex-a57-aes-1742098,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,perfmon,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("cortex-a73"), str_lit("a73,aclass,acquire-release,aes,armv8-a,crc,crypto,d32,db,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,perfmon,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("cortex-a75"), str_lit("a75,aclass,acquire-release,aes,armv8.2-a,crc,crypto,d32,db,dotprod,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,perfmon,ras,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("cortex-a76"), str_lit("a76,aclass,acquire-release,aes,armv8.2-a,crc,crypto,d32,db,dotprod,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs16,fpregs64,fullfp16,hwdiv,hwdiv-arm,mp,neon,perfmon,ras,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("cortex-a76ae"), str_lit("a76,aclass,acquire-release,aes,armv8.2-a,crc,crypto,d32,db,dotprod,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs16,fpregs64,fullfp16,hwdiv,hwdiv-arm,mp,neon,perfmon,ras,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("cortex-a77"), str_lit("a77,aclass,acquire-release,aes,armv8.2-a,crc,crypto,d32,db,dotprod,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs16,fpregs64,fullfp16,hwdiv,hwdiv-arm,mp,neon,perfmon,ras,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("cortex-a78"), str_lit("aclass,acquire-release,aes,armv8.2-a,cortex-a78,crc,crypto,d32,db,dotprod,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs16,fpregs64,fullfp16,hwdiv,hwdiv-arm,mp,neon,perfmon,ras,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("cortex-a78ae"), str_lit("aclass,acquire-release,aes,armv8.2-a,cortex-a78ae,crc,crypto,d32,db,dotprod,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs16,fpregs64,fullfp16,hwdiv,hwdiv-arm,mp,neon,perfmon,ras,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("cortex-a78c"), str_lit("a78c,aclass,acquire-release,aes,armv8.2-a,crc,crypto,d32,db,dotprod,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs16,fpregs64,fullfp16,hwdiv,hwdiv-arm,mp,neon,perfmon,ras,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("cortex-a8"), str_lit("a8,aclass,armv7-a,d32,db,dsp,fp64,fpregs,fpregs64,nonpipelined-vfp,perfmon,ret-addr-stack,slow-fp-brcc,slowfpvfmx,slowfpvmlx,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vmlx-forwarding,vmlx-hazards") }, + { str_lit("cortex-a9"), str_lit("a9,aclass,armv7-a,avoid-partial-cpsr,d32,db,dsp,expand-fp-mlx,fp16,fp64,fpregs,fpregs64,mp,muxed-units,neon-fpmovs,perfmon,prefer-vmovsr,ret-addr-stack,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vldn-align,vmlx-forwarding,vmlx-hazards") }, + { str_lit("cortex-m0"), str_lit("armv6-m,db,mclass,no-branch-predictor,noarm,strict-align,thumb-mode,v4t,v5t,v5te,v6,v6m") }, + { str_lit("cortex-m0plus"), str_lit("armv6-m,db,mclass,no-branch-predictor,noarm,strict-align,thumb-mode,v4t,v5t,v5te,v6,v6m") }, + { str_lit("cortex-m1"), str_lit("armv6-m,db,mclass,no-branch-predictor,noarm,strict-align,thumb-mode,v4t,v5t,v5te,v6,v6m") }, + { str_lit("cortex-m23"), str_lit("8msecext,acquire-release,armv8-m.base,db,hwdiv,mclass,no-branch-predictor,no-movt,noarm,strict-align,thumb-mode,v4t,v5t,v5te,v6,v6m,v7clrex,v8m") }, + { str_lit("cortex-m3"), str_lit("armv7-m,db,hwdiv,loop-align,m3,mclass,no-branch-predictor,noarm,thumb-mode,thumb2,use-misched,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m") }, + { str_lit("cortex-m33"), str_lit("8msecext,acquire-release,armv8-m.main,avoid-muls,db,dsp,fix-cmse-cve-2021-35465,fp-armv8d16sp,fp16,fpregs,hwdiv,loop-align,mclass,no-branch-predictor,noarm,slowfpvfmx,slowfpvmlx,thumb-mode,thumb2,use-misched,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,v8m.main,vfp2sp,vfp3d16sp,vfp4d16sp") }, + { str_lit("cortex-m35p"), str_lit("8msecext,acquire-release,armv8-m.main,db,dsp,fix-cmse-cve-2021-35465,fp-armv8d16sp,fp16,fpregs,hwdiv,loop-align,mclass,no-branch-predictor,noarm,slowfpvfmx,slowfpvmlx,thumb-mode,thumb2,use-misched,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,v8m.main,vfp2sp,vfp3d16sp,vfp4d16sp") }, + { str_lit("cortex-m4"), str_lit("armv7e-m,db,dsp,fp16,fpregs,hwdiv,loop-align,mclass,no-branch-predictor,noarm,slowfpvfmx,slowfpvmlx,thumb-mode,thumb2,use-misched,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2sp,vfp3d16sp,vfp4d16sp") }, + { str_lit("cortex-m52"), str_lit("8msecext,acquire-release,armv8.1-m.main,db,dsp,fp-armv8d16,fp-armv8d16sp,fp16,fp64,fpregs,fpregs16,fpregs64,fullfp16,hwdiv,lob,loop-align,mclass,mve,mve.fp,mve1beat,no-branch-predictor,noarm,pacbti,ras,slowfpvmlx,thumb-mode,thumb2,use-misched,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8.1m.main,v8m,v8m.main,vfp2,vfp2sp,vfp3d16,vfp3d16sp,vfp4d16,vfp4d16sp") }, + { str_lit("cortex-m55"), str_lit("8msecext,acquire-release,armv8.1-m.main,db,dsp,fix-cmse-cve-2021-35465,fp-armv8d16,fp-armv8d16sp,fp16,fp64,fpregs,fpregs16,fpregs64,fullfp16,hwdiv,lob,loop-align,m55,mclass,mve,mve.fp,no-branch-predictor,noarm,ras,slowfpvmlx,thumb-mode,thumb2,use-misched,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8.1m.main,v8m,v8m.main,vfp2,vfp2sp,vfp3d16,vfp3d16sp,vfp4d16,vfp4d16sp") }, + { str_lit("cortex-m7"), str_lit("armv7e-m,branch-align-64,db,dsp,fp-armv8d16,fp-armv8d16sp,fp16,fp64,fpregs,fpregs64,hwdiv,m7,mclass,noarm,thumb-mode,thumb2,use-mipipeliner,use-misched,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3d16,vfp3d16sp,vfp4d16,vfp4d16sp") }, + { str_lit("cortex-m85"), str_lit("8msecext,acquire-release,armv8.1-m.main,branch-align-64,db,dsp,fp-armv8d16,fp-armv8d16sp,fp16,fp64,fpregs,fpregs16,fpregs64,fullfp16,hwdiv,lob,m85,mclass,mve,mve.fp,noarm,pacbti,ras,thumb-mode,thumb2,use-misched,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8.1m.main,v8m,v8m.main,vfp2,vfp2sp,vfp3d16,vfp3d16sp,vfp4d16,vfp4d16sp") }, + { str_lit("cortex-r4"), str_lit("armv7-r,avoid-partial-cpsr,db,dsp,hwdiv,perfmon,r4,rclass,ret-addr-stack,thumb2,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m") }, + { str_lit("cortex-r4f"), str_lit("armv7-r,avoid-partial-cpsr,db,dsp,fp64,fpregs,fpregs64,hwdiv,perfmon,r4,rclass,ret-addr-stack,slow-fp-brcc,slowfpvfmx,slowfpvmlx,thumb2,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3d16,vfp3d16sp") }, + { str_lit("cortex-r5"), str_lit("armv7-r,avoid-partial-cpsr,db,dsp,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,perfmon,r5,rclass,ret-addr-stack,slow-fp-brcc,slowfpvfmx,slowfpvmlx,thumb2,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3d16,vfp3d16sp") }, + { str_lit("cortex-r52"), str_lit("acquire-release,armv8-r,crc,d32,db,dfb,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpao,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,perfmon,r52,rclass,thumb2,use-misched,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("cortex-r52plus"), str_lit("acquire-release,armv8-r,crc,d32,db,dfb,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpao,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,perfmon,r52plus,rclass,thumb2,use-misched,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("cortex-r7"), str_lit("armv7-r,avoid-partial-cpsr,db,dsp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,perfmon,r7,rclass,ret-addr-stack,slow-fp-brcc,slowfpvfmx,slowfpvmlx,thumb2,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3d16,vfp3d16sp") }, + { str_lit("cortex-r8"), str_lit("armv7-r,avoid-partial-cpsr,db,dsp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,perfmon,rclass,ret-addr-stack,slow-fp-brcc,slowfpvfmx,slowfpvmlx,thumb2,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3d16,vfp3d16sp") }, + { str_lit("cortex-x1"), str_lit("aclass,acquire-release,aes,armv8.2-a,cortex-x1,crc,crypto,d32,db,dotprod,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs16,fpregs64,fullfp16,hwdiv,hwdiv-arm,mp,neon,perfmon,ras,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("cortex-x1c"), str_lit("aclass,acquire-release,aes,armv8.2-a,cortex-x1c,crc,crypto,d32,db,dotprod,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs16,fpregs64,fullfp16,hwdiv,hwdiv-arm,mp,neon,perfmon,ras,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("cyclone"), str_lit("aclass,acquire-release,aes,armv8-a,avoid-movs-shop,avoid-partial-cpsr,crc,crypto,d32,db,disable-postra-scheduler,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,neonfp,perfmon,ret-addr-stack,sha2,slowfpvfmx,slowfpvmlx,swift,thumb2,trustzone,use-misched,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization,zcz") }, + { str_lit("ep9312"), str_lit("armv4t,v4t") }, + { str_lit("exynos-m3"), str_lit("aclass,acquire-release,aes,armv8-a,crc,crypto,d32,db,dont-widen-vmovs,dsp,expand-fp-mlx,exynos,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs64,fuse-aes,fuse-literals,hwdiv,hwdiv-arm,mp,neon,perfmon,prof-unpr,ret-addr-stack,sha2,slow-fp-brcc,slow-vdup32,slow-vgetlni32,slowfpvfmx,slowfpvmlx,splat-vfp-neon,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization,wide-stride-vfp,zcz") }, + { str_lit("exynos-m4"), str_lit("aclass,acquire-release,aes,armv8.2-a,crc,crypto,d32,db,dont-widen-vmovs,dotprod,dsp,expand-fp-mlx,exynos,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs16,fpregs64,fullfp16,fuse-aes,fuse-literals,hwdiv,hwdiv-arm,mp,neon,perfmon,prof-unpr,ras,ret-addr-stack,sha2,slow-fp-brcc,slow-vdup32,slow-vgetlni32,slowfpvfmx,slowfpvmlx,splat-vfp-neon,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization,wide-stride-vfp,zcz") }, + { str_lit("exynos-m5"), str_lit("aclass,acquire-release,aes,armv8.2-a,crc,crypto,d32,db,dont-widen-vmovs,dotprod,dsp,expand-fp-mlx,exynos,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs16,fpregs64,fullfp16,fuse-aes,fuse-literals,hwdiv,hwdiv-arm,mp,neon,perfmon,prof-unpr,ras,ret-addr-stack,sha2,slow-fp-brcc,slow-vdup32,slow-vgetlni32,slowfpvfmx,slowfpvmlx,splat-vfp-neon,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization,wide-stride-vfp,zcz") }, + { str_lit("generic"), str_lit("") }, + { str_lit("iwmmxt"), str_lit("armv5te,v4t,v5t,v5te") }, + { str_lit("krait"), str_lit("aclass,armv7-a,avoid-partial-cpsr,d32,db,dsp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,krait,muxed-units,perfmon,ret-addr-stack,thumb2,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,vldn-align,vmlx-forwarding") }, + { str_lit("kryo"), str_lit("aclass,acquire-release,aes,armv8-a,crc,crypto,d32,db,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,kryo,mp,neon,perfmon,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("mpcore"), str_lit("armv6k,fp64,fpregs,fpregs64,slowfpvmlx,v4t,v5t,v5te,v6,v6k,vfp2,vfp2sp") }, + { str_lit("mpcorenovfp"), str_lit("armv6k,v4t,v5t,v5te,v6,v6k") }, + { str_lit("neoverse-n1"), str_lit("aclass,acquire-release,aes,armv8.2-a,crc,crypto,d32,db,dotprod,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,perfmon,ras,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("neoverse-n2"), str_lit("aclass,acquire-release,armv9-a,bf16,crc,d32,db,dotprod,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp16fml,fp64,fpregs,fpregs16,fpregs64,fullfp16,hwdiv,hwdiv-arm,i8mm,mp,neon,perfmon,ras,sb,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8m,v9a,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("neoverse-v1"), str_lit("aclass,acquire-release,aes,armv8.4-a,bf16,crc,crypto,d32,db,dotprod,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs16,fpregs64,fullfp16,hwdiv,hwdiv-arm,i8mm,mp,neon,perfmon,ras,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8.3a,v8.4a,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("sc000"), str_lit("armv6-m,db,mclass,no-branch-predictor,noarm,strict-align,thumb-mode,v4t,v5t,v5te,v6,v6m") }, + { str_lit("sc300"), str_lit("armv7-m,db,hwdiv,m3,mclass,no-branch-predictor,noarm,thumb-mode,thumb2,use-misched,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m") }, + { str_lit("star-mc1"), str_lit("8msecext,acquire-release,armv8-m.main,avoid-muls,db,dsp,fix-cmse-cve-2021-35465,fp-armv8d16sp,fp16,fpregs,hwdiv,loop-align,mclass,no-branch-predictor,noarm,slowfpvfmx,slowfpvmlx,thumb-mode,thumb2,use-misched,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,v8m.main,vfp2sp,vfp3d16sp,vfp4d16sp") }, + { str_lit("strongarm"), str_lit("armv4") }, + { str_lit("strongarm110"), str_lit("armv4") }, + { str_lit("strongarm1100"), str_lit("armv4") }, + { str_lit("strongarm1110"), str_lit("armv4") }, + { str_lit("swift"), str_lit("aclass,armv7-a,avoid-movs-shop,avoid-partial-cpsr,d32,db,disable-postra-scheduler,dsp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neonfp,perfmon,prefer-ishst,prof-unpr,ret-addr-stack,slow-load-D-subreg,slow-odd-reg,slow-vdup32,slow-vgetlni32,slowfpvfmx,slowfpvmlx,swift,thumb2,use-misched,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,vmlx-hazards,wide-stride-vfp") }, + { str_lit("xscale"), str_lit("armv5te,v4t,v5t,v5te") }, + // TargetArch_arm64: + { str_lit("a64fx"), str_lit("CONTEXTIDREL2,a64fx,aes,aggressive-fma,arith-bcc-fusion,ccpp,complxnum,crc,el2vmsa,el3,fp-armv8,fullfp16,lor,lse,neon,pan,pan-rwv,perfmon,predictable-select-expensive,ras,rdm,sha2,store-pair-suppress,sve,uaops,use-postra-scheduler,v8.1a,v8.2a,v8a,vh") }, + { str_lit("ampere1"), str_lit("CONTEXTIDREL2,aes,aggressive-fma,altnzcv,alu-lsl-fast,am,ampere1,amvs,arith-bcc-fusion,bf16,bti,ccdp,ccidx,ccpp,cmp-bcc-fusion,complxnum,crc,dit,dotprod,ecv,el2vmsa,el3,fgt,flagm,fp-armv8,fptoint,fullfp16,fuse-address,fuse-adrp-add,fuse-aes,fuse-literals,i8mm,jsconv,ldp-aligned-only,lor,lse,lse2,mpam,neon,nv,pan,pan-rwv,pauth,perfmon,predres,rand,ras,rcpc,rcpc-immo,rdm,sb,sel2,sha2,sha3,specrestrict,ssbs,store-pair-suppress,stp-aligned-only,tlb-rmi,tracev8.4,uaops,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8a,vh") }, + { str_lit("ampere1a"), str_lit("CONTEXTIDREL2,aes,aggressive-fma,altnzcv,alu-lsl-fast,am,ampere1a,amvs,arith-bcc-fusion,bf16,bti,ccdp,ccidx,ccpp,cmp-bcc-fusion,complxnum,crc,dit,dotprod,ecv,el2vmsa,el3,fgt,flagm,fp-armv8,fptoint,fullfp16,fuse-address,fuse-addsub-2reg-const1,fuse-adrp-add,fuse-aes,fuse-literals,i8mm,jsconv,ldp-aligned-only,lor,lse,lse2,mpam,mte,neon,nv,pan,pan-rwv,pauth,perfmon,predres,rand,ras,rcpc,rcpc-immo,rdm,sb,sel2,sha2,sha3,sm4,specrestrict,ssbs,store-pair-suppress,stp-aligned-only,tlb-rmi,tracev8.4,uaops,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8a,vh") }, + { str_lit("ampere1b"), str_lit("CONTEXTIDREL2,aes,aggressive-fma,altnzcv,alu-lsl-fast,am,ampere1b,amvs,arith-bcc-fusion,bf16,bti,ccdp,ccidx,ccpp,cmp-bcc-fusion,complxnum,crc,cssc,dit,dotprod,ecv,el2vmsa,el3,enable-select-opt,fgt,flagm,fp-armv8,fptoint,fullfp16,fuse-address,fuse-adrp-add,fuse-aes,fuse-literals,hcx,i8mm,jsconv,ldp-aligned-only,lor,lse,lse2,mpam,mte,neon,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,predres,rand,ras,rcpc,rcpc-immo,rdm,sb,sel2,sha2,sha3,sm4,specrestrict,ssbs,store-pair-suppress,stp-aligned-only,tlb-rmi,tracev8.4,uaops,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8.7a,v8a,vh,wfxt,xs") }, + { str_lit("apple-a10"), str_lit("CONTEXTIDREL2,aes,alternate-sextload-cvt-f32-pattern,apple-a10,arith-bcc-fusion,arith-cbz-fusion,crc,disable-latency-sched-heuristic,el2vmsa,el3,fp-armv8,fuse-aes,fuse-crypto-eor,lor,neon,pan,perfmon,rdm,sha2,store-pair-suppress,v8a,vh,zcm-fpr64,zcm-gpr64,zcz,zcz-gp") }, + { str_lit("apple-a11"), str_lit("CONTEXTIDREL2,aes,alternate-sextload-cvt-f32-pattern,apple-a11,arith-bcc-fusion,arith-cbz-fusion,ccpp,crc,disable-latency-sched-heuristic,el2vmsa,el3,fp-armv8,fullfp16,fuse-aes,fuse-crypto-eor,lor,lse,neon,pan,pan-rwv,perfmon,ras,rdm,sha2,store-pair-suppress,uaops,v8.1a,v8.2a,v8a,vh,zcm-fpr64,zcm-gpr64,zcz,zcz-gp") }, + { str_lit("apple-a12"), str_lit("CONTEXTIDREL2,aes,alternate-sextload-cvt-f32-pattern,apple-a12,arith-bcc-fusion,arith-cbz-fusion,ccpp,complxnum,crc,disable-latency-sched-heuristic,el2vmsa,el3,fp-armv8,fullfp16,fuse-aes,fuse-crypto-eor,jsconv,lor,lse,neon,pan,pan-rwv,pauth,perfmon,ras,rcpc,rdm,sha2,store-pair-suppress,uaops,v8.1a,v8.2a,v8.3a,v8a,vh,zcm-fpr64,zcm-gpr64,zcz,zcz-gp") }, + { str_lit("apple-a13"), str_lit("CONTEXTIDREL2,aes,alternate-sextload-cvt-f32-pattern,am,apple-a13,arith-bcc-fusion,arith-cbz-fusion,ccpp,complxnum,crc,disable-latency-sched-heuristic,dit,dotprod,el2vmsa,el3,flagm,fp-armv8,fp16fml,fullfp16,fuse-aes,fuse-crypto-eor,jsconv,lor,lse,lse2,mpam,neon,nv,pan,pan-rwv,pauth,perfmon,ras,rcpc,rcpc-immo,rdm,sel2,sha2,sha3,store-pair-suppress,tlb-rmi,tracev8.4,uaops,v8.1a,v8.2a,v8.3a,v8.4a,v8a,vh,zcm-fpr64,zcm-gpr64,zcz,zcz-gp") }, + { str_lit("apple-a14"), str_lit("CONTEXTIDREL2,aes,aggressive-fma,alternate-sextload-cvt-f32-pattern,altnzcv,am,apple-a14,arith-bcc-fusion,arith-cbz-fusion,ccdp,ccpp,complxnum,crc,disable-latency-sched-heuristic,dit,dotprod,el2vmsa,el3,flagm,fp-armv8,fp16fml,fptoint,fullfp16,fuse-address,fuse-aes,fuse-arith-logic,fuse-crypto-eor,fuse-csel,fuse-literals,jsconv,lor,lse,lse2,mpam,neon,nv,pan,pan-rwv,pauth,perfmon,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,sha2,sha3,specrestrict,ssbs,store-pair-suppress,tlb-rmi,tracev8.4,uaops,v8.1a,v8.2a,v8.3a,v8.4a,v8a,vh,zcm-fpr64,zcm-gpr64,zcz,zcz-gp") }, + { str_lit("apple-a15"), str_lit("CONTEXTIDREL2,aes,alternate-sextload-cvt-f32-pattern,altnzcv,am,amvs,apple-a15,arith-bcc-fusion,arith-cbz-fusion,bf16,bti,ccdp,ccpp,complxnum,crc,disable-latency-sched-heuristic,dit,dotprod,ecv,el2vmsa,el3,fgt,flagm,fp-armv8,fp16fml,fpac,fptoint,fullfp16,fuse-address,fuse-adrp-add,fuse-aes,fuse-arith-logic,fuse-crypto-eor,fuse-csel,fuse-literals,i8mm,jsconv,lor,lse,lse2,mpam,neon,nv,pan,pan-rwv,pauth,perfmon,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,sha2,sha3,specrestrict,ssbs,store-pair-suppress,tlb-rmi,tracev8.4,uaops,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8a,vh,zcm-fpr64,zcm-gpr64,zcz,zcz-gp") }, + { str_lit("apple-a16"), str_lit("CONTEXTIDREL2,aes,alternate-sextload-cvt-f32-pattern,altnzcv,am,amvs,apple-a16,arith-bcc-fusion,arith-cbz-fusion,bf16,bti,ccdp,ccpp,complxnum,crc,disable-latency-sched-heuristic,dit,dotprod,ecv,el2vmsa,el3,fgt,flagm,fp-armv8,fp16fml,fpac,fptoint,fullfp16,fuse-address,fuse-adrp-add,fuse-aes,fuse-arith-logic,fuse-crypto-eor,fuse-csel,fuse-literals,hcx,i8mm,jsconv,lor,lse,lse2,mpam,neon,nv,pan,pan-rwv,pauth,perfmon,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,sha2,sha3,specrestrict,ssbs,store-pair-suppress,tlb-rmi,tracev8.4,uaops,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8a,vh,zcm-fpr64,zcm-gpr64,zcz,zcz-gp") }, + { str_lit("apple-a17"), str_lit("CONTEXTIDREL2,aes,alternate-sextload-cvt-f32-pattern,altnzcv,am,amvs,apple-a17,arith-bcc-fusion,arith-cbz-fusion,bf16,bti,ccdp,ccpp,complxnum,crc,disable-latency-sched-heuristic,dit,dotprod,ecv,el2vmsa,el3,fgt,flagm,fp-armv8,fp16fml,fpac,fptoint,fullfp16,fuse-address,fuse-adrp-add,fuse-aes,fuse-arith-logic,fuse-crypto-eor,fuse-csel,fuse-literals,hcx,i8mm,jsconv,lor,lse,lse2,mpam,neon,nv,pan,pan-rwv,pauth,perfmon,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,sha2,sha3,specrestrict,ssbs,store-pair-suppress,tlb-rmi,tracev8.4,uaops,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8a,vh,zcm-fpr64,zcm-gpr64,zcz,zcz-gp") }, + { str_lit("apple-a18"), str_lit("CONTEXTIDREL2,aes,alternate-sextload-cvt-f32-pattern,altnzcv,am,amvs,apple-m4,arith-bcc-fusion,arith-cbz-fusion,bf16,bti,ccdp,ccpp,complxnum,crc,disable-latency-sched-heuristic,dit,dotprod,ecv,el2vmsa,el3,fgt,flagm,fp-armv8,fp16fml,fpac,fptoint,fullfp16,fuse-address,fuse-adrp-add,fuse-aes,fuse-arith-logic,fuse-crypto-eor,fuse-csel,fuse-literals,hcx,i8mm,jsconv,lor,lse,lse2,mpam,neon,nv,pan,pan-rwv,pauth,perfmon,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,sha2,sha3,sme,sme-f64f64,sme-i16i64,sme2,specrestrict,tlb-rmi,tracev8.4,uaops,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8.7a,v8a,vh,wfxt,xs,zcm-fpr64,zcm-gpr64,zcz,zcz-gp") }, + { str_lit("apple-a7"), str_lit("aes,alternate-sextload-cvt-f32-pattern,apple-a7,arith-bcc-fusion,arith-cbz-fusion,disable-latency-sched-heuristic,el2vmsa,el3,fp-armv8,fuse-aes,fuse-crypto-eor,neon,perfmon,sha2,store-pair-suppress,v8a,zcm-fpr64,zcm-gpr64,zcz,zcz-fp-workaround,zcz-gp") }, + { str_lit("apple-a8"), str_lit("aes,alternate-sextload-cvt-f32-pattern,apple-a7,arith-bcc-fusion,arith-cbz-fusion,disable-latency-sched-heuristic,el2vmsa,el3,fp-armv8,fuse-aes,fuse-crypto-eor,neon,perfmon,sha2,store-pair-suppress,v8a,zcm-fpr64,zcm-gpr64,zcz,zcz-fp-workaround,zcz-gp") }, + { str_lit("apple-a9"), str_lit("aes,alternate-sextload-cvt-f32-pattern,apple-a7,arith-bcc-fusion,arith-cbz-fusion,disable-latency-sched-heuristic,el2vmsa,el3,fp-armv8,fuse-aes,fuse-crypto-eor,neon,perfmon,sha2,store-pair-suppress,v8a,zcm-fpr64,zcm-gpr64,zcz,zcz-fp-workaround,zcz-gp") }, + { str_lit("apple-m1"), str_lit("CONTEXTIDREL2,aes,aggressive-fma,alternate-sextload-cvt-f32-pattern,altnzcv,am,apple-a14,arith-bcc-fusion,arith-cbz-fusion,ccdp,ccpp,complxnum,crc,disable-latency-sched-heuristic,dit,dotprod,el2vmsa,el3,flagm,fp-armv8,fp16fml,fptoint,fullfp16,fuse-address,fuse-aes,fuse-arith-logic,fuse-crypto-eor,fuse-csel,fuse-literals,jsconv,lor,lse,lse2,mpam,neon,nv,pan,pan-rwv,pauth,perfmon,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,sha2,sha3,specrestrict,ssbs,store-pair-suppress,tlb-rmi,tracev8.4,uaops,v8.1a,v8.2a,v8.3a,v8.4a,v8a,vh,zcm-fpr64,zcm-gpr64,zcz,zcz-gp") }, + { str_lit("apple-m2"), str_lit("CONTEXTIDREL2,aes,alternate-sextload-cvt-f32-pattern,altnzcv,am,amvs,apple-a15,arith-bcc-fusion,arith-cbz-fusion,bf16,bti,ccdp,ccpp,complxnum,crc,disable-latency-sched-heuristic,dit,dotprod,ecv,el2vmsa,el3,fgt,flagm,fp-armv8,fp16fml,fpac,fptoint,fullfp16,fuse-address,fuse-adrp-add,fuse-aes,fuse-arith-logic,fuse-crypto-eor,fuse-csel,fuse-literals,i8mm,jsconv,lor,lse,lse2,mpam,neon,nv,pan,pan-rwv,pauth,perfmon,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,sha2,sha3,specrestrict,ssbs,store-pair-suppress,tlb-rmi,tracev8.4,uaops,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8a,vh,zcm-fpr64,zcm-gpr64,zcz,zcz-gp") }, + { str_lit("apple-m3"), str_lit("CONTEXTIDREL2,aes,alternate-sextload-cvt-f32-pattern,altnzcv,am,amvs,apple-a16,arith-bcc-fusion,arith-cbz-fusion,bf16,bti,ccdp,ccpp,complxnum,crc,disable-latency-sched-heuristic,dit,dotprod,ecv,el2vmsa,el3,fgt,flagm,fp-armv8,fp16fml,fpac,fptoint,fullfp16,fuse-address,fuse-adrp-add,fuse-aes,fuse-arith-logic,fuse-crypto-eor,fuse-csel,fuse-literals,hcx,i8mm,jsconv,lor,lse,lse2,mpam,neon,nv,pan,pan-rwv,pauth,perfmon,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,sha2,sha3,specrestrict,ssbs,store-pair-suppress,tlb-rmi,tracev8.4,uaops,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8a,vh,zcm-fpr64,zcm-gpr64,zcz,zcz-gp") }, + { str_lit("apple-m4"), str_lit("CONTEXTIDREL2,aes,alternate-sextload-cvt-f32-pattern,altnzcv,am,amvs,apple-m4,arith-bcc-fusion,arith-cbz-fusion,bf16,bti,ccdp,ccpp,complxnum,crc,disable-latency-sched-heuristic,dit,dotprod,ecv,el2vmsa,el3,fgt,flagm,fp-armv8,fp16fml,fpac,fptoint,fullfp16,fuse-address,fuse-adrp-add,fuse-aes,fuse-arith-logic,fuse-crypto-eor,fuse-csel,fuse-literals,hcx,i8mm,jsconv,lor,lse,lse2,mpam,neon,nv,pan,pan-rwv,pauth,perfmon,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,sha2,sha3,sme,sme-f64f64,sme-i16i64,sme2,specrestrict,tlb-rmi,tracev8.4,uaops,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8.7a,v8a,vh,wfxt,xs,zcm-fpr64,zcm-gpr64,zcz,zcz-gp") }, + { str_lit("apple-s10"), str_lit("CONTEXTIDREL2,aes,alternate-sextload-cvt-f32-pattern,altnzcv,am,amvs,apple-a16,arith-bcc-fusion,arith-cbz-fusion,bf16,bti,ccdp,ccpp,complxnum,crc,disable-latency-sched-heuristic,dit,dotprod,ecv,el2vmsa,el3,fgt,flagm,fp-armv8,fp16fml,fpac,fptoint,fullfp16,fuse-address,fuse-adrp-add,fuse-aes,fuse-arith-logic,fuse-crypto-eor,fuse-csel,fuse-literals,hcx,i8mm,jsconv,lor,lse,lse2,mpam,neon,nv,pan,pan-rwv,pauth,perfmon,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,sha2,sha3,specrestrict,ssbs,store-pair-suppress,tlb-rmi,tracev8.4,uaops,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8a,vh,zcm-fpr64,zcm-gpr64,zcz,zcz-gp") }, + { str_lit("apple-s4"), str_lit("CONTEXTIDREL2,aes,alternate-sextload-cvt-f32-pattern,apple-a12,arith-bcc-fusion,arith-cbz-fusion,ccpp,complxnum,crc,disable-latency-sched-heuristic,el2vmsa,el3,fp-armv8,fullfp16,fuse-aes,fuse-crypto-eor,jsconv,lor,lse,neon,pan,pan-rwv,pauth,perfmon,ras,rcpc,rdm,sha2,store-pair-suppress,uaops,v8.1a,v8.2a,v8.3a,v8a,vh,zcm-fpr64,zcm-gpr64,zcz,zcz-gp") }, + { str_lit("apple-s5"), str_lit("CONTEXTIDREL2,aes,alternate-sextload-cvt-f32-pattern,apple-a12,arith-bcc-fusion,arith-cbz-fusion,ccpp,complxnum,crc,disable-latency-sched-heuristic,el2vmsa,el3,fp-armv8,fullfp16,fuse-aes,fuse-crypto-eor,jsconv,lor,lse,neon,pan,pan-rwv,pauth,perfmon,ras,rcpc,rdm,sha2,store-pair-suppress,uaops,v8.1a,v8.2a,v8.3a,v8a,vh,zcm-fpr64,zcm-gpr64,zcz,zcz-gp") }, + { str_lit("apple-s6"), str_lit("CONTEXTIDREL2,aes,alternate-sextload-cvt-f32-pattern,am,apple-a13,arith-bcc-fusion,arith-cbz-fusion,ccpp,complxnum,crc,disable-latency-sched-heuristic,dit,dotprod,el2vmsa,el3,flagm,fp-armv8,fp16fml,fullfp16,fuse-aes,fuse-crypto-eor,jsconv,lor,lse,lse2,mpam,neon,nv,pan,pan-rwv,pauth,perfmon,ras,rcpc,rcpc-immo,rdm,sel2,sha2,sha3,store-pair-suppress,tlb-rmi,tracev8.4,uaops,v8.1a,v8.2a,v8.3a,v8.4a,v8a,vh,zcm-fpr64,zcm-gpr64,zcz,zcz-gp") }, + { str_lit("apple-s7"), str_lit("CONTEXTIDREL2,aes,alternate-sextload-cvt-f32-pattern,am,apple-a13,arith-bcc-fusion,arith-cbz-fusion,ccpp,complxnum,crc,disable-latency-sched-heuristic,dit,dotprod,el2vmsa,el3,flagm,fp-armv8,fp16fml,fullfp16,fuse-aes,fuse-crypto-eor,jsconv,lor,lse,lse2,mpam,neon,nv,pan,pan-rwv,pauth,perfmon,ras,rcpc,rcpc-immo,rdm,sel2,sha2,sha3,store-pair-suppress,tlb-rmi,tracev8.4,uaops,v8.1a,v8.2a,v8.3a,v8.4a,v8a,vh,zcm-fpr64,zcm-gpr64,zcz,zcz-gp") }, + { str_lit("apple-s8"), str_lit("CONTEXTIDREL2,aes,alternate-sextload-cvt-f32-pattern,am,apple-a13,arith-bcc-fusion,arith-cbz-fusion,ccpp,complxnum,crc,disable-latency-sched-heuristic,dit,dotprod,el2vmsa,el3,flagm,fp-armv8,fp16fml,fullfp16,fuse-aes,fuse-crypto-eor,jsconv,lor,lse,lse2,mpam,neon,nv,pan,pan-rwv,pauth,perfmon,ras,rcpc,rcpc-immo,rdm,sel2,sha2,sha3,store-pair-suppress,tlb-rmi,tracev8.4,uaops,v8.1a,v8.2a,v8.3a,v8.4a,v8a,vh,zcm-fpr64,zcm-gpr64,zcz,zcz-gp") }, + { str_lit("apple-s9"), str_lit("CONTEXTIDREL2,aes,alternate-sextload-cvt-f32-pattern,altnzcv,am,amvs,apple-a16,arith-bcc-fusion,arith-cbz-fusion,bf16,bti,ccdp,ccpp,complxnum,crc,disable-latency-sched-heuristic,dit,dotprod,ecv,el2vmsa,el3,fgt,flagm,fp-armv8,fp16fml,fpac,fptoint,fullfp16,fuse-address,fuse-adrp-add,fuse-aes,fuse-arith-logic,fuse-crypto-eor,fuse-csel,fuse-literals,hcx,i8mm,jsconv,lor,lse,lse2,mpam,neon,nv,pan,pan-rwv,pauth,perfmon,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,sha2,sha3,specrestrict,ssbs,store-pair-suppress,tlb-rmi,tracev8.4,uaops,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8a,vh,zcm-fpr64,zcm-gpr64,zcz,zcz-gp") }, + { str_lit("carmel"), str_lit("CONTEXTIDREL2,aes,carmel,ccpp,crc,el2vmsa,el3,fp-armv8,fullfp16,lor,lse,neon,pan,pan-rwv,ras,rdm,sha2,uaops,v8.1a,v8.2a,v8a,vh") }, + { str_lit("cobalt-100"), str_lit("CONTEXTIDREL2,altnzcv,alu-lsl-fast,am,bf16,bti,ccdp,ccidx,ccpp,complxnum,crc,dit,dotprod,el2vmsa,el3,enable-select-opt,ete,flagm,fp-armv8,fp16fml,fpac,fptoint,fullfp16,fuse-adrp-add,fuse-aes,i8mm,jsconv,lor,lse,lse2,mpam,mte,neon,neoversen2,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,specrestrict,ssbs,sve,sve-bitperm,sve2,tlb-rmi,tracev8.4,trbe,uaops,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8a,v9a,vh") }, + { str_lit("cortex-a320"), str_lit("CONTEXTIDREL2,a320,altnzcv,am,amvs,bf16,bti,ccdp,ccidx,ccpp,complxnum,crc,dit,dotprod,ecv,el2vmsa,el3,ete,fgt,flagm,fp-armv8,fp16fml,fptoint,fullfp16,fuse-adrp-add,fuse-aes,hcx,i8mm,jsconv,lor,lse,lse2,mpam,mte,neon,nv,pan,pan-rwv,pauth,perfmon,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,specrestrict,ssbs,sve,sve-bitperm,sve2,tlb-rmi,tracev8.4,trbe,uaops,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8.7a,v8a,v9.1a,v9.2a,v9a,vh,wfxt,xs") }, + { str_lit("cortex-a34"), str_lit("a35,aes,crc,el2vmsa,el3,fp-armv8,neon,perfmon,sha2,v8a") }, + { str_lit("cortex-a35"), str_lit("a35,aes,crc,el2vmsa,el3,fp-armv8,neon,perfmon,sha2,v8a") }, + { str_lit("cortex-a510"), str_lit("CONTEXTIDREL2,a510,altnzcv,am,bf16,bti,ccdp,ccidx,ccpp,complxnum,crc,dit,dotprod,el2vmsa,el3,ete,flagm,fp-armv8,fp16fml,fpac,fptoint,fullfp16,fuse-adrp-add,fuse-aes,i8mm,jsconv,lor,lse,lse2,mpam,mte,neon,nv,pan,pan-rwv,pauth,perfmon,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,specrestrict,ssbs,sve,sve-bitperm,sve2,tlb-rmi,tracev8.4,trbe,uaops,use-fixed-over-scalable-if-equal-cost,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8a,v9a,vh") }, + { str_lit("cortex-a520"), str_lit("CONTEXTIDREL2,a520,altnzcv,am,amvs,bf16,bti,ccdp,ccidx,ccpp,complxnum,crc,dit,dotprod,ecv,el2vmsa,el3,ete,fgt,flagm,fp-armv8,fp16fml,fpac,fptoint,fullfp16,fuse-adrp-add,fuse-aes,hcx,i8mm,jsconv,lor,lse,lse2,mpam,mte,neon,nv,pan,pan-rwv,pauth,perfmon,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,specrestrict,ssbs,sve,sve-bitperm,sve2,tlb-rmi,tracev8.4,trbe,uaops,use-fixed-over-scalable-if-equal-cost,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8.7a,v8a,v9.1a,v9.2a,v9a,vh,wfxt,xs") }, + { str_lit("cortex-a520ae"), str_lit("CONTEXTIDREL2,a520ae,altnzcv,am,amvs,bf16,bti,ccdp,ccidx,ccpp,complxnum,crc,dit,dotprod,ecv,el2vmsa,el3,ete,fgt,flagm,fp-armv8,fp16fml,fpac,fptoint,fullfp16,fuse-adrp-add,fuse-aes,hcx,i8mm,jsconv,lor,lse,lse2,mpam,mte,neon,nv,pan,pan-rwv,pauth,perfmon,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,specrestrict,ssbs,sve,sve-bitperm,sve2,tlb-rmi,tracev8.4,trbe,uaops,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8.7a,v8a,v9.1a,v9.2a,v9a,vh,wfxt,xs") }, + { str_lit("cortex-a53"), str_lit("a53,aes,balance-fp-ops,crc,el2vmsa,el3,fp-armv8,fuse-adrp-add,fuse-aes,neon,perfmon,sha2,use-postra-scheduler,v8a") }, + { str_lit("cortex-a55"), str_lit("CONTEXTIDREL2,a55,aes,ccpp,crc,dotprod,el2vmsa,el3,fp-armv8,fullfp16,fuse-address,fuse-adrp-add,fuse-aes,lor,lse,neon,pan,pan-rwv,perfmon,ras,rcpc,rdm,sha2,uaops,use-postra-scheduler,v8.1a,v8.2a,v8a,vh") }, + { str_lit("cortex-a57"), str_lit("a57,addr-lsl-slow-14,aes,balance-fp-ops,crc,el2vmsa,el3,enable-select-opt,fp-armv8,fuse-adrp-add,fuse-aes,fuse-literals,neon,perfmon,predictable-select-expensive,sha2,use-postra-scheduler,v8a") }, + { str_lit("cortex-a65"), str_lit("CONTEXTIDREL2,a65,aes,ccpp,crc,dotprod,el2vmsa,el3,enable-select-opt,fp-armv8,fullfp16,fuse-address,fuse-adrp-add,fuse-aes,fuse-literals,lor,lse,neon,pan,pan-rwv,perfmon,predictable-select-expensive,ras,rcpc,rdm,sha2,ssbs,uaops,v8.1a,v8.2a,v8a,vh") }, + { str_lit("cortex-a65ae"), str_lit("CONTEXTIDREL2,a65,aes,ccpp,crc,dotprod,el2vmsa,el3,enable-select-opt,fp-armv8,fullfp16,fuse-address,fuse-adrp-add,fuse-aes,fuse-literals,lor,lse,neon,pan,pan-rwv,perfmon,predictable-select-expensive,ras,rcpc,rdm,sha2,ssbs,uaops,v8.1a,v8.2a,v8a,vh") }, + { str_lit("cortex-a710"), str_lit("CONTEXTIDREL2,a710,altnzcv,alu-lsl-fast,am,bf16,bti,ccdp,ccidx,ccpp,cmp-bcc-fusion,complxnum,crc,dit,dotprod,el2vmsa,el3,enable-select-opt,ete,flagm,fp-armv8,fp16fml,fpac,fptoint,fullfp16,fuse-adrp-add,fuse-aes,i8mm,jsconv,lor,lse,lse2,mpam,mte,neon,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,specrestrict,ssbs,sve,sve-bitperm,sve2,tlb-rmi,tracev8.4,trbe,uaops,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8a,v9a,vh") }, + { str_lit("cortex-a715"), str_lit("CONTEXTIDREL2,a715,altnzcv,alu-lsl-fast,am,bf16,bti,ccdp,ccidx,ccpp,cmp-bcc-fusion,complxnum,crc,dit,dotprod,el2vmsa,el3,enable-select-opt,ete,flagm,fp-armv8,fp16fml,fpac,fptoint,fullfp16,fuse-adrp-add,fuse-aes,i8mm,jsconv,lor,lse,lse2,mpam,mte,neon,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,spe,specrestrict,ssbs,sve,sve-bitperm,sve2,tlb-rmi,tracev8.4,trbe,uaops,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8a,v9a,vh") }, + { str_lit("cortex-a72"), str_lit("a72,addr-lsl-slow-14,aes,crc,el2vmsa,el3,enable-select-opt,fp-armv8,fuse-adrp-add,fuse-aes,fuse-literals,neon,perfmon,predictable-select-expensive,sha2,v8a") }, + { str_lit("cortex-a720"), str_lit("CONTEXTIDREL2,a720,altnzcv,alu-lsl-fast,am,amvs,bf16,bti,ccdp,ccidx,ccpp,cmp-bcc-fusion,complxnum,crc,dit,dotprod,ecv,el2vmsa,el3,enable-select-opt,ete,fgt,flagm,fp-armv8,fp16fml,fpac,fptoint,fullfp16,fuse-adrp-add,fuse-aes,hcx,i8mm,jsconv,lor,lse,lse2,mpam,mte,neon,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,spe,spe-eef,specrestrict,ssbs,sve,sve-bitperm,sve2,tlb-rmi,tracev8.4,trbe,uaops,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8.7a,v8a,v9.1a,v9.2a,v9a,vh,wfxt,xs") }, + { str_lit("cortex-a720ae"), str_lit("CONTEXTIDREL2,a720ae,altnzcv,alu-lsl-fast,am,amvs,bf16,bti,ccdp,ccidx,ccpp,cmp-bcc-fusion,complxnum,crc,dit,dotprod,ecv,el2vmsa,el3,enable-select-opt,ete,fgt,flagm,fp-armv8,fp16fml,fpac,fptoint,fullfp16,fuse-adrp-add,fuse-aes,hcx,i8mm,jsconv,lor,lse,lse2,mpam,mte,neon,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,spe,spe-eef,specrestrict,ssbs,sve,sve-bitperm,sve2,tlb-rmi,tracev8.4,trbe,uaops,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8.7a,v8a,v9.1a,v9.2a,v9a,vh,wfxt,xs") }, + { str_lit("cortex-a725"), str_lit("CONTEXTIDREL2,altnzcv,alu-lsl-fast,am,amvs,bf16,bti,ccdp,ccidx,ccpp,cmp-bcc-fusion,complxnum,cortex-a725,crc,dit,dotprod,ecv,el2vmsa,el3,enable-select-opt,ete,fgt,flagm,fp-armv8,fp16fml,fpac,fptoint,fullfp16,fuse-adrp-add,fuse-aes,hcx,i8mm,jsconv,lor,lse,lse2,mpam,mte,neon,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,spe,spe-eef,specrestrict,ssbs,sve,sve-bitperm,sve2,tlb-rmi,tracev8.4,trbe,uaops,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8.7a,v8a,v9.1a,v9.2a,v9a,vh,wfxt,xs") }, + { str_lit("cortex-a73"), str_lit("a73,addr-lsl-slow-14,aes,crc,el2vmsa,el3,enable-select-opt,fp-armv8,fuse-adrp-add,fuse-aes,neon,perfmon,predictable-select-expensive,sha2,v8a") }, + { str_lit("cortex-a75"), str_lit("CONTEXTIDREL2,a75,addr-lsl-slow-14,aes,ccpp,crc,dotprod,el2vmsa,el3,enable-select-opt,fp-armv8,fullfp16,fuse-adrp-add,fuse-aes,lor,lse,neon,pan,pan-rwv,perfmon,predictable-select-expensive,ras,rcpc,rdm,sha2,uaops,v8.1a,v8.2a,v8a,vh") }, + { str_lit("cortex-a76"), str_lit("CONTEXTIDREL2,a76,addr-lsl-slow-14,aes,alu-lsl-fast,ccpp,crc,dotprod,el2vmsa,el3,enable-select-opt,fp-armv8,fullfp16,fuse-adrp-add,fuse-aes,lor,lse,neon,pan,pan-rwv,perfmon,predictable-select-expensive,ras,rcpc,rdm,sha2,ssbs,uaops,v8.1a,v8.2a,v8a,vh") }, + { str_lit("cortex-a76ae"), str_lit("CONTEXTIDREL2,a76,addr-lsl-slow-14,aes,alu-lsl-fast,ccpp,crc,dotprod,el2vmsa,el3,enable-select-opt,fp-armv8,fullfp16,fuse-adrp-add,fuse-aes,lor,lse,neon,pan,pan-rwv,perfmon,predictable-select-expensive,ras,rcpc,rdm,sha2,ssbs,uaops,v8.1a,v8.2a,v8a,vh") }, + { str_lit("cortex-a77"), str_lit("CONTEXTIDREL2,a77,addr-lsl-slow-14,aes,alu-lsl-fast,ccpp,cmp-bcc-fusion,crc,dotprod,el2vmsa,el3,enable-select-opt,fp-armv8,fullfp16,fuse-adrp-add,fuse-aes,lor,lse,neon,pan,pan-rwv,perfmon,predictable-select-expensive,ras,rcpc,rdm,sha2,ssbs,uaops,v8.1a,v8.2a,v8a,vh") }, + { str_lit("cortex-a78"), str_lit("CONTEXTIDREL2,a78,addr-lsl-slow-14,aes,alu-lsl-fast,ccpp,cmp-bcc-fusion,crc,dotprod,el2vmsa,el3,enable-select-opt,fp-armv8,fullfp16,fuse-adrp-add,fuse-aes,lor,lse,neon,pan,pan-rwv,perfmon,predictable-select-expensive,ras,rcpc,rdm,sha2,spe,ssbs,uaops,use-postra-scheduler,v8.1a,v8.2a,v8a,vh") }, + { str_lit("cortex-a78ae"), str_lit("CONTEXTIDREL2,a78ae,addr-lsl-slow-14,aes,alu-lsl-fast,ccpp,cmp-bcc-fusion,crc,dotprod,el2vmsa,el3,enable-select-opt,fp-armv8,fullfp16,fuse-adrp-add,fuse-aes,lor,lse,neon,pan,pan-rwv,perfmon,predictable-select-expensive,ras,rcpc,rdm,sha2,spe,ssbs,uaops,use-postra-scheduler,v8.1a,v8.2a,v8a,vh") }, + { str_lit("cortex-a78c"), str_lit("CONTEXTIDREL2,a78c,addr-lsl-slow-14,aes,alu-lsl-fast,ccpp,cmp-bcc-fusion,crc,dotprod,el2vmsa,el3,enable-select-opt,flagm,fp-armv8,fullfp16,fuse-adrp-add,fuse-aes,lor,lse,neon,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,ras,rcpc,rdm,sha2,spe,ssbs,uaops,use-postra-scheduler,v8.1a,v8.2a,v8a,vh") }, + { str_lit("cortex-r82"), str_lit("CONTEXTIDREL2,ccdp,ccpp,complxnum,cortex-r82,crc,dit,dotprod,flagm,fp-armv8,fp16fml,fpac,fullfp16,jsconv,lse,neon,pan,pan-rwv,pauth,perfmon,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,specrestrict,ssbs,tlb-rmi,tracev8.4,uaops,use-postra-scheduler,v8r") }, + { str_lit("cortex-r82ae"), str_lit("CONTEXTIDREL2,ccdp,ccpp,complxnum,cortex-r82ae,crc,dit,dotprod,flagm,fp-armv8,fp16fml,fpac,fullfp16,jsconv,lse,neon,pan,pan-rwv,pauth,perfmon,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,specrestrict,ssbs,tlb-rmi,tracev8.4,uaops,use-postra-scheduler,v8r") }, + { str_lit("cortex-x1"), str_lit("CONTEXTIDREL2,addr-lsl-slow-14,aes,alu-lsl-fast,ccpp,cmp-bcc-fusion,cortex-x1,crc,dotprod,el2vmsa,el3,enable-select-opt,fp-armv8,fullfp16,fuse-adrp-add,fuse-aes,lor,lse,neon,pan,pan-rwv,perfmon,predictable-select-expensive,ras,rcpc,rdm,sha2,spe,ssbs,uaops,use-postra-scheduler,v8.1a,v8.2a,v8a,vh") }, + { str_lit("cortex-x1c"), str_lit("CONTEXTIDREL2,addr-lsl-slow-14,aes,alu-lsl-fast,ccpp,cmp-bcc-fusion,cortex-x1,crc,dotprod,el2vmsa,el3,enable-select-opt,flagm,fp-armv8,fullfp16,fuse-adrp-add,fuse-aes,lor,lse,lse2,neon,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,ras,rcpc,rcpc-immo,rdm,sha2,spe,ssbs,uaops,use-postra-scheduler,v8.1a,v8.2a,v8a,vh") }, + { str_lit("cortex-x2"), str_lit("CONTEXTIDREL2,altnzcv,alu-lsl-fast,am,bf16,bti,ccdp,ccidx,ccpp,cmp-bcc-fusion,complxnum,cortex-x2,crc,dit,dotprod,el2vmsa,el3,enable-select-opt,ete,flagm,fp-armv8,fp16fml,fpac,fptoint,fullfp16,fuse-adrp-add,fuse-aes,i8mm,jsconv,lor,lse,lse2,mpam,mte,neon,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,specrestrict,ssbs,sve,sve-bitperm,sve2,tlb-rmi,tracev8.4,trbe,uaops,use-fixed-over-scalable-if-equal-cost,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8a,v9a,vh") }, + { str_lit("cortex-x3"), str_lit("CONTEXTIDREL2,altnzcv,alu-lsl-fast,am,avoid-ldapur,bf16,bti,ccdp,ccidx,ccpp,complxnum,cortex-x3,crc,dit,dotprod,el2vmsa,el3,enable-select-opt,ete,flagm,fp-armv8,fp16fml,fpac,fptoint,fullfp16,fuse-adrp-add,fuse-aes,i8mm,jsconv,lor,lse,lse2,mpam,mte,neon,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,spe,specrestrict,ssbs,sve,sve-bitperm,sve2,tlb-rmi,tracev8.4,trbe,uaops,use-fixed-over-scalable-if-equal-cost,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8a,v9a,vh") }, + { str_lit("cortex-x4"), str_lit("CONTEXTIDREL2,altnzcv,alu-lsl-fast,am,amvs,avoid-ldapur,bf16,bti,ccdp,ccidx,ccpp,complxnum,cortex-x4,crc,dit,dotprod,ecv,el2vmsa,el3,enable-select-opt,ete,fgt,flagm,fp-armv8,fp16fml,fpac,fptoint,fullfp16,fuse-adrp-add,fuse-aes,hcx,i8mm,jsconv,lor,lse,lse2,mpam,mte,neon,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,spe,spe-eef,specrestrict,ssbs,sve,sve-bitperm,sve2,tlb-rmi,tracev8.4,trbe,uaops,use-fixed-over-scalable-if-equal-cost,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8.7a,v8a,v9.1a,v9.2a,v9a,vh,wfxt,xs") }, + { str_lit("cortex-x925"), str_lit("CONTEXTIDREL2,altnzcv,alu-lsl-fast,am,amvs,avoid-ldapur,bf16,bti,ccdp,ccidx,ccpp,complxnum,cortex-x925,crc,dit,dotprod,ecv,el2vmsa,el3,enable-select-opt,ete,fgt,flagm,fp-armv8,fp16fml,fpac,fptoint,fullfp16,fuse-adrp-add,fuse-aes,hcx,i8mm,jsconv,lor,lse,lse2,mpam,mte,neon,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,spe,spe-eef,specrestrict,ssbs,sve,sve-bitperm,sve2,tlb-rmi,tracev8.4,trbe,uaops,use-fixed-over-scalable-if-equal-cost,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8.7a,v8a,v9.1a,v9.2a,v9a,vh,wfxt,xs") }, + { str_lit("cyclone"), str_lit("aes,alternate-sextload-cvt-f32-pattern,apple-a7,arith-bcc-fusion,arith-cbz-fusion,disable-latency-sched-heuristic,el2vmsa,el3,fp-armv8,fuse-aes,fuse-crypto-eor,neon,perfmon,sha2,store-pair-suppress,v8a,zcm-fpr64,zcm-gpr64,zcz,zcz-fp-workaround,zcz-gp") }, + { str_lit("exynos-m3"), str_lit("aes,alu-lsl-fast,crc,el2vmsa,el3,exynos-cheap-as-move,exynosm3,force-32bit-jump-tables,fp-armv8,fuse-address,fuse-adrp-add,fuse-aes,fuse-csel,fuse-literals,neon,perfmon,predictable-select-expensive,sha2,store-pair-suppress,use-postra-scheduler,v8a") }, + { str_lit("exynos-m4"), str_lit("CONTEXTIDREL2,aes,alu-lsl-fast,arith-bcc-fusion,arith-cbz-fusion,ccpp,crc,dotprod,el2vmsa,el3,exynos-cheap-as-move,exynosm4,force-32bit-jump-tables,fp-armv8,fullfp16,fuse-address,fuse-adrp-add,fuse-aes,fuse-arith-logic,fuse-csel,fuse-literals,lor,lse,neon,pan,pan-rwv,perfmon,ras,rdm,sha2,store-pair-suppress,uaops,use-postra-scheduler,v8.1a,v8.2a,v8a,vh,zcz,zcz-gp") }, + { str_lit("exynos-m5"), str_lit("CONTEXTIDREL2,aes,alu-lsl-fast,arith-bcc-fusion,arith-cbz-fusion,ccpp,crc,dotprod,el2vmsa,el3,exynos-cheap-as-move,exynosm4,force-32bit-jump-tables,fp-armv8,fullfp16,fuse-address,fuse-adrp-add,fuse-aes,fuse-arith-logic,fuse-csel,fuse-literals,lor,lse,neon,pan,pan-rwv,perfmon,ras,rdm,sha2,store-pair-suppress,uaops,use-postra-scheduler,v8.1a,v8.2a,v8a,vh,zcz,zcz-gp") }, + { str_lit("falkor"), str_lit("aes,alu-lsl-fast,crc,el2vmsa,el3,falkor,fp-armv8,neon,perfmon,predictable-select-expensive,rdm,sha2,slow-strqro-store,store-pair-suppress,use-postra-scheduler,v8a,zcz,zcz-gp") }, + { str_lit("fujitsu-monaka"), str_lit("CONTEXTIDREL2,aes,altnzcv,am,amvs,arith-bcc-fusion,bf16,bti,ccdp,ccidx,ccpp,clrbhb,complxnum,crc,dit,dotprod,ecv,el2vmsa,el3,enable-select-opt,ete,faminmax,fgt,flagm,fp-armv8,fp16fml,fp8,fp8dot2,fp8dot4,fp8fma,fpac,fptoint,fujitsu-monaka,fullfp16,hbc,hcx,i8mm,jsconv,lor,ls64,lse,lse2,lut,mec,mops,mpam,neon,nmi,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,predres,rand,ras,rcpc,rcpc-immo,rdm,rme,sb,sel2,sha2,sha3,sm4,specres2,specrestrict,ssbs,sve,sve-aes,sve-bitperm,sve-sha3,sve-sm4,sve2,tlb-rmi,tracev8.4,trbe,uaops,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8.7a,v8.8a,v8a,v9.1a,v9.2a,v9.3a,v9a,vh,wfxt,xs") }, + { str_lit("gb10"), str_lit("CONTEXTIDREL2,aes,altnzcv,alu-lsl-fast,am,amvs,avoid-ldapur,bf16,bti,ccdp,ccidx,ccpp,complxnum,cortex-x925,crc,dit,dotprod,ecv,el2vmsa,el3,enable-select-opt,ete,fgt,flagm,fp-armv8,fp16fml,fpac,fptoint,fullfp16,fuse-adrp-add,fuse-aes,hcx,i8mm,jsconv,lor,lse,lse2,mpam,mte,neon,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,sha2,sha3,sm4,spe,spe-eef,specrestrict,ssbs,sve,sve-aes,sve-bitperm,sve-sha3,sve-sm4,sve2,tlb-rmi,tracev8.4,trbe,uaops,use-fixed-over-scalable-if-equal-cost,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8.7a,v8a,v9.1a,v9.2a,v9a,vh,wfxt,xs") }, + { str_lit("generic"), str_lit("enable-select-opt,ete,fp-armv8,fuse-adrp-add,fuse-aes,neon,trbe,use-postra-scheduler") }, + { str_lit("grace"), str_lit("CONTEXTIDREL2,aes,altnzcv,alu-lsl-fast,am,avoid-ldapur,bf16,bti,ccdp,ccidx,ccpp,cmp-bcc-fusion,complxnum,crc,disable-latency-sched-heuristic,dit,dotprod,el2vmsa,el3,enable-select-opt,ete,flagm,fp-armv8,fp16fml,fpac,fptoint,fullfp16,fuse-adrp-add,fuse-aes,i8mm,jsconv,lor,lse,lse2,mpam,mte,neon,neoversev2,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,predres,rand,ras,rcpc,rcpc-immo,rdm,sb,sel2,sha2,sha3,sm4,spe,specrestrict,ssbs,sve,sve-aes,sve-bitperm,sve-sha3,sve-sm4,sve2,tlb-rmi,tracev8.4,trbe,uaops,use-fixed-over-scalable-if-equal-cost,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8a,v9a,vh") }, + { str_lit("kryo"), str_lit("aes,alu-lsl-fast,crc,el2vmsa,el3,fp-armv8,kryo,neon,perfmon,predictable-select-expensive,sha2,store-pair-suppress,use-postra-scheduler,v8a,zcz,zcz-gp") }, + { str_lit("neoverse-512tvb"), str_lit("CONTEXTIDREL2,aes,alu-lsl-fast,am,bf16,ccdp,ccidx,ccpp,complxnum,crc,dit,dotprod,el2vmsa,el3,enable-select-opt,flagm,fp-armv8,fp16fml,fpac,fullfp16,fuse-adrp-add,fuse-aes,i8mm,jsconv,lor,lse,lse2,mpam,neon,neoverse512tvb,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,rand,ras,rcpc,rcpc-immo,rdm,sel2,sha2,sha3,sm4,spe,ssbs,sve,tlb-rmi,tracev8.4,uaops,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8a,vh") }, + { str_lit("neoverse-e1"), str_lit("CONTEXTIDREL2,aes,ccpp,crc,dotprod,el2vmsa,el3,fp-armv8,fullfp16,fuse-adrp-add,fuse-aes,lor,lse,neon,neoversee1,pan,pan-rwv,perfmon,ras,rcpc,rdm,sha2,ssbs,uaops,use-postra-scheduler,v8.1a,v8.2a,v8a,vh") }, + { str_lit("neoverse-n1"), str_lit("CONTEXTIDREL2,addr-lsl-slow-14,aes,alu-lsl-fast,ccpp,crc,dotprod,el2vmsa,el3,enable-select-opt,fp-armv8,fullfp16,fuse-adrp-add,fuse-aes,lor,lse,neon,neoversen1,pan,pan-rwv,perfmon,predictable-select-expensive,ras,rcpc,rdm,sha2,spe,ssbs,uaops,use-postra-scheduler,v8.1a,v8.2a,v8a,vh") }, + { str_lit("neoverse-n2"), str_lit("CONTEXTIDREL2,altnzcv,alu-lsl-fast,am,bf16,bti,ccdp,ccidx,ccpp,complxnum,crc,dit,dotprod,el2vmsa,el3,enable-select-opt,ete,flagm,fp-armv8,fp16fml,fpac,fptoint,fullfp16,fuse-adrp-add,fuse-aes,i8mm,jsconv,lor,lse,lse2,mpam,mte,neon,neoversen2,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,specrestrict,ssbs,sve,sve-bitperm,sve2,tlb-rmi,tracev8.4,trbe,uaops,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8a,v9a,vh") }, + { str_lit("neoverse-n3"), str_lit("CONTEXTIDREL2,altnzcv,alu-lsl-fast,am,amvs,bf16,bti,ccdp,ccidx,ccpp,complxnum,crc,dit,dotprod,ecv,el2vmsa,el3,enable-select-opt,ete,fgt,flagm,fp-armv8,fp16fml,fpac,fptoint,fullfp16,fuse-adrp-add,fuse-aes,hcx,i8mm,jsconv,lor,lse,lse2,mpam,mte,neon,neoversen3,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,predres,rand,ras,rcpc,rcpc-immo,rdm,sb,sel2,spe,spe-eef,specrestrict,ssbs,sve,sve-bitperm,sve2,tlb-rmi,tracev8.4,trbe,uaops,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8.7a,v8a,v9.1a,v9.2a,v9a,vh,wfxt,xs") }, + { str_lit("neoverse-v1"), str_lit("CONTEXTIDREL2,addr-lsl-slow-14,aes,alu-lsl-fast,am,bf16,ccdp,ccidx,ccpp,complxnum,crc,dit,dotprod,el2vmsa,el3,enable-select-opt,flagm,fp-armv8,fp16fml,fullfp16,fuse-adrp-add,fuse-aes,i8mm,jsconv,lor,lse,lse2,mpam,neon,neoversev1,no-sve-fp-ld1r,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,rand,ras,rcpc,rcpc-immo,rdm,sel2,sha2,sha3,sm4,spe,ssbs,sve,tlb-rmi,tracev8.4,uaops,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8a,vh") }, + { str_lit("neoverse-v2"), str_lit("CONTEXTIDREL2,altnzcv,alu-lsl-fast,am,avoid-ldapur,bf16,bti,ccdp,ccidx,ccpp,cmp-bcc-fusion,complxnum,crc,disable-latency-sched-heuristic,dit,dotprod,el2vmsa,el3,enable-select-opt,ete,flagm,fp-armv8,fp16fml,fpac,fptoint,fullfp16,fuse-adrp-add,fuse-aes,i8mm,jsconv,lor,lse,lse2,mpam,mte,neon,neoversev2,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,predres,rand,ras,rcpc,rcpc-immo,rdm,sb,sel2,spe,specrestrict,ssbs,sve,sve-bitperm,sve2,tlb-rmi,tracev8.4,trbe,uaops,use-fixed-over-scalable-if-equal-cost,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8a,v9a,vh") }, + { str_lit("neoverse-v3"), str_lit("CONTEXTIDREL2,altnzcv,alu-lsl-fast,am,amvs,avoid-ldapur,bf16,brbe,bti,ccdp,ccidx,ccpp,complxnum,crc,dit,dotprod,ecv,el2vmsa,el3,enable-select-opt,ete,fgt,flagm,fp-armv8,fp16fml,fpac,fptoint,fullfp16,fuse-adrp-add,fuse-aes,hcx,i8mm,jsconv,lor,ls64,lse,lse2,mpam,mte,neon,neoversev3,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,predres,rand,ras,rcpc,rcpc-immo,rdm,rme,sb,sel2,spe,spe-eef,specrestrict,ssbs,sve,sve-bitperm,sve2,tlb-rmi,tracev8.4,trbe,uaops,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8.7a,v8a,v9.1a,v9.2a,v9a,vh,wfxt,xs") }, + { str_lit("neoverse-v3ae"), str_lit("CONTEXTIDREL2,altnzcv,alu-lsl-fast,am,amvs,avoid-ldapur,bf16,brbe,bti,ccdp,ccidx,ccpp,complxnum,crc,dit,dotprod,ecv,el2vmsa,el3,enable-select-opt,ete,fgt,flagm,fp-armv8,fp16fml,fpac,fptoint,fullfp16,fuse-adrp-add,fuse-aes,hcx,i8mm,jsconv,lor,ls64,lse,lse2,mpam,mte,neon,neoversev3AE,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,predres,rand,ras,rcpc,rcpc-immo,rdm,rme,sb,sel2,spe,spe-eef,specrestrict,ssbs,sve,sve-bitperm,sve2,tlb-rmi,tracev8.4,trbe,uaops,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8.7a,v8a,v9.1a,v9.2a,v9a,vh,wfxt,xs") }, + { str_lit("olympus"), str_lit("CONTEXTIDREL2,aes,altnzcv,alu-lsl-fast,am,amvs,bf16,brbe,bti,ccdp,ccidx,ccpp,chk,cmp-bcc-fusion,complxnum,crc,dit,dotprod,ecv,el2vmsa,el3,enable-select-opt,ete,faminmax,fgt,flagm,fp-armv8,fp16fml,fp8,fp8dot2,fp8dot4,fp8fma,fpac,fptoint,fullfp16,fuse-adrp-add,fuse-aes,hcx,i8mm,jsconv,lor,ls64,lse,lse2,lut,mec,mpam,mte,neon,nv,olympus,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,predres,rand,ras,rcpc,rcpc-immo,rdm,rme,sb,sel2,sha2,sha3,sm4,spe,spe-eef,specrestrict,ssbs,sve,sve-aes,sve-bitperm,sve-sha3,sve-sm4,sve2,tlb-rmi,tracev8.4,trbe,uaops,use-fixed-over-scalable-if-equal-cost,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8.7a,v8a,v9.1a,v9.2a,v9a,vh,wfxt,xs") }, + { str_lit("oryon-1"), str_lit("CONTEXTIDREL2,aes,altnzcv,am,amvs,bf16,bti,ccdp,ccidx,ccpp,complxnum,crc,dit,dotprod,ecv,el2vmsa,el3,enable-select-opt,fgt,flagm,fp-armv8,fp16fml,fptoint,fullfp16,fuse-address,fuse-adrp-add,fuse-aes,fuse-crypto-eor,i8mm,jsconv,lor,lse,lse2,mpam,neon,nv,oryon-1,pan,pan-rwv,pauth,perfmon,predres,rand,ras,rcpc,rcpc-immo,rdm,sb,sel2,sha2,sha3,sm4,spe,specrestrict,ssbs,tlb-rmi,tracev8.4,uaops,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8a,vh") }, + { str_lit("saphira"), str_lit("CONTEXTIDREL2,aes,alu-lsl-fast,am,ccidx,ccpp,complxnum,crc,dit,dotprod,el2vmsa,el3,flagm,fp-armv8,jsconv,lor,lse,lse2,mpam,neon,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,ras,rcpc,rcpc-immo,rdm,saphira,sel2,sha2,spe,store-pair-suppress,tlb-rmi,tracev8.4,uaops,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8a,vh,zcz,zcz-gp") }, + { str_lit("thunderx"), str_lit("aes,crc,el2vmsa,el3,fp-armv8,neon,perfmon,predictable-select-expensive,sha2,store-pair-suppress,thunderx,use-postra-scheduler,v8a") }, + { str_lit("thunderx2t99"), str_lit("CONTEXTIDREL2,aes,aggressive-fma,arith-bcc-fusion,crc,el2vmsa,el3,fp-armv8,lor,lse,neon,pan,predictable-select-expensive,rdm,sha2,store-pair-suppress,thunderx2t99,use-postra-scheduler,v8.1a,v8a,vh") }, + { str_lit("thunderx3t110"), str_lit("CONTEXTIDREL2,aes,aggressive-fma,arith-bcc-fusion,balance-fp-ops,ccidx,ccpp,complxnum,crc,el2vmsa,el3,fp-armv8,jsconv,lor,lse,neon,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,ras,rcpc,rdm,sha2,store-pair-suppress,strict-align,thunderx3t110,uaops,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8a,vh") }, + { str_lit("thunderxt81"), str_lit("aes,crc,el2vmsa,el3,fp-armv8,neon,perfmon,predictable-select-expensive,sha2,store-pair-suppress,thunderxt81,use-postra-scheduler,v8a") }, + { str_lit("thunderxt83"), str_lit("aes,crc,el2vmsa,el3,fp-armv8,neon,perfmon,predictable-select-expensive,sha2,store-pair-suppress,thunderxt83,use-postra-scheduler,v8a") }, + { str_lit("thunderxt88"), str_lit("aes,crc,el2vmsa,el3,fp-armv8,neon,perfmon,predictable-select-expensive,sha2,store-pair-suppress,thunderxt88,use-postra-scheduler,v8a") }, + { str_lit("tsv110"), str_lit("CONTEXTIDREL2,aes,ccpp,complxnum,crc,dotprod,el2vmsa,el3,fp-armv8,fp16fml,fullfp16,fuse-aes,jsconv,lor,lse,neon,pan,pan-rwv,perfmon,ras,rdm,sha2,spe,store-pair-suppress,tsv110,uaops,use-postra-scheduler,v8.1a,v8.2a,v8a,vh") }, + // TargetArch_wasm32: + { str_lit("bleeding-edge"), str_lit("atomics,bulk-memory,bulk-memory-opt,call-indirect-overlong,exception-handling,extended-const,fp16,multimemory,multivalue,mutable-globals,nontrapping-fptoint,reference-types,relaxed-simd,sign-ext,simd128,tail-call") }, + { str_lit("generic"), str_lit("bulk-memory,bulk-memory-opt,call-indirect-overlong,multivalue,mutable-globals,nontrapping-fptoint,reference-types,sign-ext") }, + { str_lit("lime1"), str_lit("bulk-memory-opt,call-indirect-overlong,extended-const,multivalue,mutable-globals,nontrapping-fptoint,sign-ext") }, + { str_lit("mvp"), str_lit("") }, + // TargetArch_wasm64p32: + { str_lit("bleeding-edge"), str_lit("atomics,bulk-memory,bulk-memory-opt,call-indirect-overlong,exception-handling,extended-const,fp16,multimemory,multivalue,mutable-globals,nontrapping-fptoint,reference-types,relaxed-simd,sign-ext,simd128,tail-call") }, + { str_lit("generic"), str_lit("bulk-memory,bulk-memory-opt,call-indirect-overlong,multivalue,mutable-globals,nontrapping-fptoint,reference-types,sign-ext") }, + { str_lit("lime1"), str_lit("bulk-memory-opt,call-indirect-overlong,extended-const,multivalue,mutable-globals,nontrapping-fptoint,sign-ext") }, + { str_lit("mvp"), str_lit("") }, + // TargetArch_riscv64: + { str_lit("andes-45-series"), str_lit("andes45,no-default-unroll,short-forward-branch-opt,use-postra-scheduler") }, + { str_lit("andes-a25"), str_lit("32bit,a,c,d,f,i,m,xandesperf,zaamo,zalrsc,zca,zicsr,zifencei,zmmul") }, + { str_lit("andes-a45"), str_lit("32bit,a,andes45,c,d,f,i,m,no-default-unroll,short-forward-branch-opt,use-postra-scheduler,xandesperf,zaamo,zalrsc,zca,zicsr,zifencei,zmmul") }, + { str_lit("andes-ax25"), str_lit("64bit,a,c,d,f,i,m,xandesperf,zaamo,zalrsc,zca,zicsr,zifencei,zmmul") }, + { str_lit("andes-ax45"), str_lit("64bit,a,andes45,c,d,f,i,m,no-default-unroll,short-forward-branch-opt,use-postra-scheduler,xandesperf,zaamo,zalrsc,zca,zicsr,zifencei,zmmul") }, + { str_lit("andes-ax45mpv"), str_lit("64bit,a,andes45,c,d,f,i,m,no-default-unroll,short-forward-branch-opt,use-postra-scheduler,v,xandesperf,zaamo,zalrsc,zca,zicsr,zifencei,zmmul,zve32f,zve32x,zve64d,zve64f,zve64x,zvl128b,zvl32b,zvl64b") }, + { str_lit("andes-n45"), str_lit("32bit,a,andes45,c,d,f,i,m,no-default-unroll,short-forward-branch-opt,use-postra-scheduler,xandesperf,zaamo,zalrsc,zca,zicsr,zifencei,zmmul") }, + { str_lit("andes-nx45"), str_lit("64bit,a,andes45,c,d,f,i,m,no-default-unroll,short-forward-branch-opt,use-postra-scheduler,xandesperf,zaamo,zalrsc,zca,zicsr,zifencei,zmmul") }, + { str_lit("generic"), str_lit("64bit,i,optimized-nf2-segment-load-store") }, + { str_lit("generic-ooo"), str_lit("") }, + { str_lit("generic-rv32"), str_lit("32bit,i,optimized-nf2-segment-load-store") }, + { str_lit("generic-rv64"), str_lit("64bit,i,optimized-nf2-segment-load-store") }, + { str_lit("mips-p8700"), str_lit("64bit,a,c,d,f,i,m,mips-p8700,xmipscbop,xmipscmov,xmipslsp,zaamo,zalrsc,zba,zbb,zca,zicsr,zifencei,zmmul") }, + { str_lit("rocket"), str_lit("") }, + { str_lit("rocket-rv32"), str_lit("32bit,i,zicsr,zifencei") }, + { str_lit("rocket-rv64"), str_lit("64bit,i,zicsr,zifencei") }, + { str_lit("rp2350-hazard3"), str_lit("32bit,a,c,i,m,zaamo,zalrsc,zba,zbb,zbkb,zbs,zca,zcb,zcmp,zicsr,zifencei,zmmul") }, + { str_lit("sifive-7-series"), str_lit("no-default-unroll,short-forward-branch-opt,sifive7,use-postra-scheduler") }, + { str_lit("sifive-e20"), str_lit("32bit,c,i,m,zca,zicsr,zifencei,zmmul") }, + { str_lit("sifive-e21"), str_lit("32bit,a,c,i,m,zaamo,zalrsc,zca,zicsr,zifencei,zmmul") }, + { str_lit("sifive-e24"), str_lit("32bit,a,c,f,i,m,zaamo,zalrsc,zca,zicsr,zifencei,zmmul") }, + { str_lit("sifive-e31"), str_lit("32bit,a,c,i,m,zaamo,zalrsc,zca,zicsr,zifencei,zmmul") }, + { str_lit("sifive-e34"), str_lit("32bit,a,c,f,i,m,zaamo,zalrsc,zca,zicsr,zifencei,zmmul") }, + { str_lit("sifive-e76"), str_lit("32bit,a,c,f,i,m,no-default-unroll,short-forward-branch-opt,sifive7,use-postra-scheduler,zaamo,zalrsc,zca,zicsr,zifencei,zmmul") }, + { str_lit("sifive-p450"), str_lit("64bit,a,auipc-addi-fusion,b,c,conditional-cmv-fusion,d,f,i,lui-addi-fusion,m,no-default-unroll,unaligned-scalar-mem,unaligned-vector-mem,use-postra-scheduler,za64rs,zaamo,zalrsc,zba,zbb,zbs,zca,zfhmin,zic64b,zicbom,zicbop,zicboz,ziccamoa,ziccif,zicclsm,ziccrse,zicntr,zicsr,zifencei,zihintntl,zihintpause,zihpm,zkt,zmmul") }, + { str_lit("sifive-p470"), str_lit("64bit,a,auipc-addi-fusion,b,c,conditional-cmv-fusion,d,f,i,lui-addi-fusion,m,no-default-unroll,no-sink-splat-operands,unaligned-scalar-mem,unaligned-vector-mem,use-postra-scheduler,v,vxrm-pipeline-flush,xsifivecdiscarddlone,xsifivecflushdlone,za64rs,zaamo,zalrsc,zba,zbb,zbs,zca,zfhmin,zic64b,zicbom,zicbop,zicboz,ziccamoa,ziccif,zicclsm,ziccrse,zicntr,zicsr,zifencei,zihintntl,zihintpause,zihpm,zkt,zmmul,zvbb,zvbc,zve32f,zve32x,zve64d,zve64f,zve64x,zvkb,zvkg,zvkn,zvknc,zvkned,zvkng,zvknhb,zvks,zvksc,zvksed,zvksg,zvksh,zvkt,zvl128b,zvl32b,zvl64b") }, + { str_lit("sifive-p550"), str_lit("64bit,a,auipc-addi-fusion,c,conditional-cmv-fusion,d,f,i,lui-addi-fusion,m,no-default-unroll,use-postra-scheduler,zaamo,zalrsc,zba,zbb,zca,zicsr,zifencei,zmmul") }, + { str_lit("sifive-p670"), str_lit("64bit,a,auipc-addi-fusion,b,c,conditional-cmv-fusion,d,f,i,lui-addi-fusion,m,no-default-unroll,no-sink-splat-operands,unaligned-scalar-mem,unaligned-vector-mem,use-postra-scheduler,v,vxrm-pipeline-flush,za64rs,zaamo,zalrsc,zba,zbb,zbs,zca,zfhmin,zic64b,zicbom,zicbop,zicboz,ziccamoa,ziccif,zicclsm,ziccrse,zicntr,zicsr,zifencei,zihintntl,zihintpause,zihpm,zkt,zmmul,zvbb,zvbc,zve32f,zve32x,zve64d,zve64f,zve64x,zvkb,zvkg,zvkn,zvknc,zvkned,zvkng,zvknhb,zvks,zvksc,zvksed,zvksg,zvksh,zvkt,zvl128b,zvl32b,zvl64b") }, + { str_lit("sifive-p870"), str_lit("64bit,a,auipc-addi-fusion,b,c,conditional-cmv-fusion,d,f,i,lui-addi-fusion,m,no-default-unroll,no-sink-splat-operands,supm,unaligned-scalar-mem,unaligned-vector-mem,use-postra-scheduler,v,vxrm-pipeline-flush,za64rs,zaamo,zalrsc,zama16b,zawrs,zba,zbb,zbs,zca,zcb,zcmop,zfa,zfbfmin,zfh,zfhmin,zic64b,zicbom,zicbop,zicboz,ziccamoa,ziccif,zicclsm,ziccrse,zicntr,zicond,zicsr,zifencei,zihintntl,zihintpause,zihpm,zimop,zkr,zkt,zmmul,zvbb,zvbc,zve32f,zve32x,zve64d,zve64f,zve64x,zvfbfmin,zvfbfwma,zvfh,zvfhmin,zvkb,zvkg,zvkn,zvknc,zvkned,zvkng,zvknhb,zvks,zvksc,zvksed,zvksg,zvksh,zvkt,zvl128b,zvl32b,zvl64b") }, + { str_lit("sifive-s21"), str_lit("64bit,a,c,i,m,zaamo,zalrsc,zca,zicsr,zifencei,zmmul") }, + { str_lit("sifive-s51"), str_lit("64bit,a,c,i,m,zaamo,zalrsc,zca,zicsr,zifencei,zmmul") }, + { str_lit("sifive-s54"), str_lit("64bit,a,c,d,f,i,m,zaamo,zalrsc,zca,zicsr,zifencei,zmmul") }, + { str_lit("sifive-s76"), str_lit("64bit,a,c,d,f,i,m,no-default-unroll,short-forward-branch-opt,sifive7,use-postra-scheduler,zaamo,zalrsc,zca,zicsr,zifencei,zihintpause,zmmul") }, + { str_lit("sifive-u54"), str_lit("64bit,a,c,d,f,i,m,zaamo,zalrsc,zca,zicsr,zifencei,zmmul") }, + { str_lit("sifive-u74"), str_lit("64bit,a,c,d,f,i,m,no-default-unroll,short-forward-branch-opt,sifive7,use-postra-scheduler,zaamo,zalrsc,zca,zicsr,zifencei,zmmul") }, + { str_lit("sifive-x280"), str_lit("64bit,a,c,d,dlen-factor-2,f,i,m,no-default-unroll,optimized-nf2-segment-load-store,optimized-zero-stride-load,short-forward-branch-opt,sifive7,use-postra-scheduler,v,vl-dependent-latency,zaamo,zalrsc,zba,zbb,zca,zfh,zfhmin,zicsr,zifencei,zmmul,zve32f,zve32x,zve64d,zve64f,zve64x,zvfh,zvfhmin,zvl128b,zvl256b,zvl32b,zvl512b,zvl64b") }, + { str_lit("sifive-x390"), str_lit("64bit,a,b,c,d,dlen-factor-2,experimental-zicfilp,experimental-zicfiss,f,i,m,no-default-unroll,optimized-nf2-segment-load-store,optimized-zero-stride-load,short-forward-branch-opt,sifive7,use-postra-scheduler,v,vl-dependent-latency,xsifivecdiscarddlone,xsifivecflushdlone,za64rs,zaamo,zalrsc,zawrs,zba,zbb,zbs,zca,zcb,zcmop,zfa,zfbfmin,zfh,zfhmin,zic64b,zicbom,zicbop,zicboz,ziccamoa,ziccif,ziccrse,zicntr,zicond,zicsr,zifencei,zihintntl,zihintpause,zihpm,zimop,zkr,zkt,zmmul,zvbb,zve32f,zve32x,zve64d,zve64f,zve64x,zvfbfmin,zvfbfwma,zvfh,zvfhmin,zvkb,zvkt,zvl1024b,zvl128b,zvl256b,zvl32b,zvl512b,zvl64b") }, + { str_lit("spacemit-x60"), str_lit("64bit,a,b,c,d,dlen-factor-2,f,i,m,optimized-nf2-segment-load-store,optimized-nf3-segment-load-store,optimized-nf4-segment-load-store,ssccptr,sscofpmf,sscounterenw,sstc,sstvala,sstvecd,svade,svbare,svinval,svnapot,svpbmt,unaligned-scalar-mem,v,vxrm-pipeline-flush,za64rs,zaamo,zalrsc,zba,zbb,zbc,zbkc,zbs,zca,zfh,zfhmin,zic64b,zicbom,zicbop,zicboz,ziccamoa,ziccif,zicclsm,ziccrse,zicntr,zicond,zicsr,zifencei,zihintpause,zihpm,zkt,zmmul,zve32f,zve32x,zve64d,zve64f,zve64x,zvfh,zvfhmin,zvkt,zvl128b,zvl256b,zvl32b,zvl64b") }, + { str_lit("syntacore-scr1-base"), str_lit("32bit,c,i,no-default-unroll,zca,zicsr,zifencei") }, + { str_lit("syntacore-scr1-max"), str_lit("32bit,c,i,m,no-default-unroll,zca,zicsr,zifencei,zmmul") }, + { str_lit("syntacore-scr3-rv32"), str_lit("32bit,c,i,m,no-default-unroll,use-postra-scheduler,zca,zicsr,zifencei,zmmul") }, + { str_lit("syntacore-scr3-rv64"), str_lit("64bit,a,c,i,m,no-default-unroll,use-postra-scheduler,zaamo,zalrsc,zca,zicsr,zifencei,zmmul") }, + { str_lit("syntacore-scr4-rv32"), str_lit("32bit,c,d,f,i,m,no-default-unroll,use-postra-scheduler,zca,zicsr,zifencei,zmmul") }, + { str_lit("syntacore-scr4-rv64"), str_lit("64bit,a,c,d,f,i,m,no-default-unroll,use-postra-scheduler,zaamo,zalrsc,zca,zicsr,zifencei,zmmul") }, + { str_lit("syntacore-scr5-rv32"), str_lit("32bit,a,c,d,f,i,m,no-default-unroll,use-postra-scheduler,zaamo,zalrsc,zca,zicsr,zifencei,zmmul") }, + { str_lit("syntacore-scr5-rv64"), str_lit("64bit,a,c,d,f,i,m,no-default-unroll,use-postra-scheduler,zaamo,zalrsc,zca,zicsr,zifencei,zmmul") }, + { str_lit("syntacore-scr7"), str_lit("64bit,a,c,d,f,i,m,no-default-unroll,use-postra-scheduler,v,zaamo,zalrsc,zba,zbb,zbc,zbkb,zbkc,zbkx,zbs,zca,zicsr,zifencei,zkn,zknd,zkne,zknh,zmmul,zve32f,zve32x,zve64d,zve64f,zve64x,zvl128b,zvl32b,zvl64b") }, + { str_lit("tt-ascalon-d8"), str_lit("64bit,a,b,c,d,f,h,i,log-vrgather,m,no-default-unroll,optimized-zero-stride-load,sha,shcounterenw,shgatpa,shtvala,shvsatpa,shvstvala,shvstvecd,smaia,ssaia,ssccptr,sscofpmf,sscounterenw,ssnpm,ssstateen,ssstrict,sstc,sstvala,sstvecd,ssu64xl,supm,svade,svbare,svinval,svnapot,svpbmt,unaligned-scalar-mem,unaligned-vector-mem,use-postra-scheduler,v,za64rs,zaamo,zalrsc,zawrs,zba,zbb,zbs,zca,zcb,zcmop,zfa,zfbfmin,zfh,zfhmin,zic64b,zicbom,zicbop,zicboz,ziccamoa,ziccif,zicclsm,ziccrse,zicntr,zicond,zicsr,zifencei,zihintntl,zihintpause,zihpm,zimop,zkt,zmmul,zvbb,zvbc,zve32f,zve32x,zve64d,zve64f,zve64x,zvfbfmin,zvfbfwma,zvfh,zvfhmin,zvkb,zvkg,zvkn,zvkned,zvkng,zvknhb,zvkt,zvl128b,zvl256b,zvl32b,zvl64b") }, + { str_lit("veyron-v1"), str_lit("64bit,a,auipc-addi-fusion,c,d,f,i,ld-add-fusion,lui-addi-fusion,m,shifted-zextw-fusion,ventana-veyron,xventanacondops,zaamo,zalrsc,zba,zbb,zbc,zbs,zca,zexth-fusion,zextw-fusion,zicbom,zicbop,zicboz,zicntr,zicsr,zifencei,zihintpause,zihpm,zmmul") }, + { str_lit("xiangshan-kunminghu"), str_lit("64bit,a,b,c,d,f,h,i,m,no-default-unroll,sha,shcounterenw,shgatpa,shifted-zextw-fusion,shtvala,shvsatpa,shvstvala,shvstvecd,smaia,smcsrind,smdbltrp,smmpm,smnpm,smrnmi,smstateen,ssaia,ssccptr,sscofpmf,sscounterenw,sscsrind,ssdbltrp,ssnpm,sspm,ssstateen,ssstrict,sstc,sstvala,sstvecd,ssu64xl,supm,svade,svbare,svinval,svnapot,svpbmt,v,za64rs,zaamo,zacas,zalrsc,zawrs,zba,zbb,zbc,zbkb,zbkc,zbkx,zbs,zca,zcb,zcmop,zexth-fusion,zextw-fusion,zfa,zfh,zfhmin,zic64b,zicbom,zicbop,zicboz,ziccamoa,ziccif,zicclsm,ziccrse,zicntr,zicond,zicsr,zifencei,zihintntl,zihintpause,zihpm,zimop,zkn,zknd,zkne,zknh,zks,zksed,zksh,zkt,zmmul,zvbb,zve32f,zve32x,zve64d,zve64f,zve64x,zvfh,zvfhmin,zvkb,zvkt,zvl128b,zvl32b,zvl64b") }, + { str_lit("xiangshan-nanhu"), str_lit("64bit,a,c,d,f,i,m,no-default-unroll,shifted-zextw-fusion,svinval,zaamo,zalrsc,zba,zbb,zbc,zbkb,zbkc,zbkx,zbs,zca,zexth-fusion,zextw-fusion,zicbom,zicboz,zicsr,zifencei,zkn,zknd,zkne,zknh,zksed,zksh,zmmul") }, +}; +#elif LLVM_VERSION_MAJOR == 20 // Generated with the featuregen script in `misc/featuregen` gb_global String target_microarch_list[TargetArch_COUNT] = { // TargetArch_Invalid: diff --git a/src/bundle_command.cpp b/src/bundle_command.cpp index cd0cd589f..7abd48104 100644 --- a/src/bundle_command.cpp +++ b/src/bundle_command.cpp @@ -83,7 +83,7 @@ i32 bundle_android(String original_init_directory) { return 1; } - int *dir_numbers = gb_alloc_array(temporary_allocator(), int, possible_valid_dirs.count); + int *dir_numbers = temporary_alloc_array<int>(possible_valid_dirs.count); char buf[1024] = {}; for_array(i, possible_valid_dirs) { diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index a08382c9a..1b3e6912c 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -13,6 +13,7 @@ gb_global BuiltinTypeIsProc *builtin_type_is_procs[BuiltinProc__type_simple_bool nullptr, // BuiltinProc__type_simple_boolean_begin is_type_boolean, + is_type_bit_field, is_type_integer, is_type_rune, is_type_float, @@ -20,8 +21,11 @@ gb_global BuiltinTypeIsProc *builtin_type_is_procs[BuiltinProc__type_simple_bool is_type_quaternion, is_type_string, is_type_string16, + is_type_cstring, + is_type_cstring16, is_type_typeid, is_type_any, + is_type_endian_platform, is_type_endian_little, is_type_endian_big, @@ -32,8 +36,8 @@ gb_global BuiltinTypeIsProc *builtin_type_is_procs[BuiltinProc__type_simple_bool is_type_indexable, is_type_sliceable, is_type_comparable, - is_type_simple_compare, - is_type_nearly_simple_compare, + is_type_simple_compare, // easily compared using memcmp + is_type_nearly_simple_compare, // easily compared using memcmp (including floats) is_type_dereferenceable, is_type_valid_for_keys, is_type_valid_for_matrix_elems, @@ -45,16 +49,15 @@ gb_global BuiltinTypeIsProc *builtin_type_is_procs[BuiltinProc__type_simple_bool is_type_enumerated_array, is_type_slice, is_type_dynamic_array, - is_type_map, is_type_struct, is_type_union, is_type_enum, is_type_proc, is_type_bit_set, - is_type_bit_field, is_type_simd_vector, is_type_matrix, + is_type_raw_union, is_type_polymorphic_record_specialized, is_type_polymorphic_record_unspecialized, @@ -210,7 +213,7 @@ gb_internal ObjcMsgKind get_objc_proc_kind(Type *return_type) { return ObjcMsg_normal; } -gb_internal void add_objc_proc_type(CheckerContext *c, Ast *call, Type *return_type, Slice<Type *> param_types) { +void add_objc_proc_type(CheckerContext *c, Ast *call, Type *return_type, Slice<Type *> param_types) { ObjcMsgKind kind = get_objc_proc_kind(return_type); Scope *scope = create_scope(c->info, nullptr); @@ -248,6 +251,12 @@ gb_internal void add_objc_proc_type(CheckerContext *c, Ast *call, Type *return_t try_to_add_package_dependency(c, "runtime", "objc_msgSend_fpret"); try_to_add_package_dependency(c, "runtime", "objc_msgSend_fp2ret"); try_to_add_package_dependency(c, "runtime", "objc_msgSend_stret"); + + Slice<Ast *> args = call->CallExpr.args; + if (args.count > 0 && args[0]->tav.objc_super_target) { + try_to_add_package_dependency(c, "runtime", "objc_msgSendSuper2"); + try_to_add_package_dependency(c, "runtime", "objc_msgSendSuper2_stret"); + } } gb_internal bool is_constant_string(CheckerContext *c, String const &builtin_name, Ast *expr, String *name_) { @@ -354,7 +363,7 @@ gb_internal bool check_builtin_objc_procedure(CheckerContext *c, Operand *operan } isize const arg_offset = 1; - auto param_types = slice_make<Type *>(permanent_allocator(), ce->args.count-arg_offset); + auto param_types = permanent_slice_make<Type *>(ce->args.count-arg_offset); param_types[0] = t_objc_id; param_types[1] = sel_type; @@ -462,12 +471,12 @@ gb_internal bool check_builtin_objc_procedure(CheckerContext *c, Operand *operan { // NOTE(harold): The last argument specified in the call is the handler proc, // any other arguments before it are capture by-copy arguments. - auto param_operands = slice_make<Operand>(permanent_allocator(), ce->args.count); + auto param_operands = permanent_slice_make<Operand>(ce->args.count); isize capture_arg_count = ce->args.count - 1; - // NOTE(harold): The first parameter is already checked at check_builtin_procedure(). - // Checking again would invalidate the Entity -> Value map for direct parameters if it's the handler proc. + // NOTE(harold): The first argument is already checked at check_builtin_procedure(). + // Checking again would invalidate the Entity -> Value map for direct arguments if it's the handler proc. param_operands[0] = *operand; for (isize i = 0; i < ce->args.count-1; i++) { @@ -680,6 +689,52 @@ gb_internal bool check_builtin_objc_procedure(CheckerContext *c, Operand *operan operand->mode = Addressing_Value; return true; } break; + + case BuiltinProc_objc_super: + { + // Must be a pointer to an Objective-C object. + Type *objc_obj = operand->type; + if (!is_type_objc_ptr_to_object(objc_obj)) { + gbString e = expr_to_string(operand->expr); + gbString t = type_to_string(objc_obj); + error(operand->expr, "'%.*s' expected a pointer to an Objective-C object, but got '%s' of type %s", LIT(builtin_name), e, t); + gb_string_free(t); + gb_string_free(e); + return false; + } + + if (operand->mode != Addressing_Value && operand->mode != Addressing_Variable) { + gbString e = expr_to_string(operand->expr); + gbString t = type_to_string(operand->type); + error(operand->expr, "'%.*s' expression '%s', of type %s, must be a value or variable.", LIT(builtin_name), e, t); + gb_string_free(t); + gb_string_free(e); + return false; + } + + Type *obj_type = type_deref(objc_obj); + GB_ASSERT(obj_type->kind == Type_Named); + + // NOTE(harold) Track original type before transforming it to the superclass. + // This is needed because objc_msgSendSuper2 must start its search on the subclass, not the superclass. + call->tav.objc_super_target = obj_type; + + // The superclass type must be known at compile time. We require this so that the selector method expressions + // methods are resolved to the superclass's methods instead of the subclass's. + Type *superclass = obj_type->Named.type_name->TypeName.objc_superclass; + if (superclass == nullptr) { + gbString t = type_to_string(obj_type); + error(operand->expr, "'%.*s' target object '%.*s' does not have an Objective-C superclass. One must be set via the @(objc_superclass) attribute", LIT(builtin_name), t); + gb_string_free(t); + return false; + } + + GB_ASSERT(superclass->Named.type_name->TypeName.objc_class_name.len > 0); + + operand->type = alloc_type_pointer(superclass); + return true; + + } break; } } @@ -2430,6 +2485,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As case BuiltinProc_min: case BuiltinProc_max: case BuiltinProc_type_is_subtype_of: + case BuiltinProc_type_is_superset_of: case BuiltinProc_objc_send: case BuiltinProc_objc_find_selector: case BuiltinProc_objc_find_class: @@ -2515,6 +2571,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As case BuiltinProc_objc_register_class: case BuiltinProc_objc_ivar_get: case BuiltinProc_objc_block: + case BuiltinProc_objc_super: return check_builtin_objc_procedure(c, operand, call, id, type_hint); case BuiltinProc___entry_point: @@ -3554,7 +3611,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As } case BuiltinProc_compress_values: { - Operand *ops = gb_alloc_array(temporary_allocator(), Operand, ce->args.count); + Operand *ops = temporary_alloc_array<Operand>(ce->args.count); isize value_count = 0; @@ -3685,9 +3742,9 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As operand->mode = Addressing_Value; } else { Type *st = alloc_type_struct_complete(); - st->Struct.fields = slice_make<Entity *>(permanent_allocator(), value_count); - st->Struct.tags = gb_alloc_array(permanent_allocator(), String, value_count); - st->Struct.offsets = gb_alloc_array(permanent_allocator(), i64, value_count); + st->Struct.fields = permanent_slice_make<Entity *>(value_count); + st->Struct.tags = permanent_alloc_array<String>(value_count); + st->Struct.offsets = permanent_alloc_array<i64>(value_count); Scope *scope = create_scope(c->info, nullptr); @@ -4387,7 +4444,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As elem = alloc_type_struct(); elem->Struct.scope = s; elem->Struct.fields = slice_from_array(fields); - elem->Struct.tags = gb_alloc_array(permanent_allocator(), String, fields.count); + elem->Struct.tags = permanent_alloc_array<String>(fields.count); elem->Struct.node = dummy_node_struct; type_set_offsets(elem); wait_signal_set(&elem->Struct.fields_wait_signal); @@ -4419,7 +4476,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As gb_string_free(s); return false; } - auto types = slice_make<Type *>(permanent_allocator(), t->Struct.fields.count-1); + auto types = permanent_slice_make<Type *>(t->Struct.fields.count-1); for_array(i, types) { Entity *f = t->Struct.fields[i]; GB_ASSERT(f->type->kind == Type_MultiPointer); @@ -4712,6 +4769,42 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As break; } + case BuiltinProc_constant_floor: + case BuiltinProc_constant_trunc: + case BuiltinProc_constant_ceil: + case BuiltinProc_constant_round: + { + Operand o = {}; + check_expr(c, &o, ce->args[0]); + + if (!is_type_integer_or_float(o.type) && (o.mode != Addressing_Constant)) { + error(ce->args[0], "Expected a constant number for '%.*s'", LIT(builtin_name)); + return false; + } + operand->mode = Addressing_Constant; + operand->type = o.type; + + ExactValue value = o.value; + if (value.kind == ExactValue_Integer) { + // do nothing + } else if (value.kind == ExactValue_Float) { + f64 f = value.value_float; + switch (id) { + case BuiltinProc_constant_floor: f = floor(f); break; + case BuiltinProc_constant_trunc: f = trunc(f); break; + case BuiltinProc_constant_ceil: f = ceil(f); break; + case BuiltinProc_constant_round: f = round(f); break; + default: + GB_PANIC("Unhandled built-in: %.*s", LIT(builtin_name)); + break; + } + value = exact_value_float(f); + } + + operand->value = value; + break; + } + case BuiltinProc_soa_struct: { Operand x = {}; Operand y = {}; @@ -4755,8 +4848,8 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As if (is_type_array(elem)) { Type *old_array = base_type(elem); soa_struct = alloc_type_struct(); - soa_struct->Struct.fields = slice_make<Entity *>(heap_allocator(), cast(isize)old_array->Array.count); - soa_struct->Struct.tags = gb_alloc_array(permanent_allocator(), String, cast(isize)old_array->Array.count); + soa_struct->Struct.fields = permanent_slice_make<Entity *>(cast(isize)old_array->Array.count); + soa_struct->Struct.tags = permanent_alloc_array<String>(cast(isize)old_array->Array.count); soa_struct->Struct.node = operand->expr; soa_struct->Struct.soa_kind = StructSoa_Fixed; soa_struct->Struct.soa_elem = elem; @@ -4788,8 +4881,8 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As Type *old_struct = base_type(elem); soa_struct = alloc_type_struct(); - soa_struct->Struct.fields = slice_make<Entity *>(heap_allocator(), old_struct->Struct.fields.count); - soa_struct->Struct.tags = gb_alloc_array(permanent_allocator(), String, old_struct->Struct.fields.count); + soa_struct->Struct.fields = permanent_slice_make<Entity *>(old_struct->Struct.fields.count); + soa_struct->Struct.tags = permanent_alloc_array<String>(old_struct->Struct.fields.count); soa_struct->Struct.node = operand->expr; soa_struct->Struct.soa_kind = StructSoa_Fixed; soa_struct->Struct.soa_elem = elem; @@ -4829,6 +4922,138 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As break; } + case BuiltinProc_concatenate: { + Operand lhs = {}; + + check_expr_with_type_hint(c, &lhs, ce->args[0], type_hint); + if (lhs.mode == Addressing_Invalid) { + return false; + } + if (lhs.mode != Addressing_Constant) { + error(lhs.expr, "'%.*s' expects a constant array or slice", LIT(builtin_name)); + return false; + } + operand->type = lhs.type; + operand->mode = Addressing_Value; + + if (!is_type_slice(lhs.type) && !is_type_array(lhs.type)) { + gbString a = type_to_string(lhs.type); + error(lhs.expr, "'%.*s' expects a constant array or slice, got %s", LIT(builtin_name), a); + gb_string_free(a); + return false; + } + if (lhs.value.kind != ExactValue_Compound) { + gbString a = exact_value_to_string(lhs.value); + error(lhs.expr, "Expected a compound literal value for '%.*s', got '%s'", LIT(builtin_name), a); + gb_string_free(a); + return false; + } + + ast_node(lhs_cl, CompoundLit, lhs.value.value_compound); + + for (Ast *elem : lhs_cl->elems) { + if (elem->kind == Ast_FieldValue) { + error(elem, "'%.*s' does not allow the use of 'field = value' to be concatenated together", LIT(builtin_name)); + return false; + } + } + + Type *elem_type = base_any_array_type(lhs.type); + + for (isize i = 1; i < ce->args.count; i++) { + Operand extra = {}; + if (is_type_slice(lhs.type)) { + check_expr_with_type_hint(c, &extra, ce->args[i], lhs.type); + } else { + check_expr(c, &extra, ce->args[i]); + } + if (extra.mode == Addressing_Invalid) { + return false; + } + if (extra.mode != Addressing_Constant) { + error(extra.expr, "'%.*s' expects a constant array or slice", LIT(builtin_name)); + return false; + } + + if (is_type_slice(lhs.type)) { + if (!are_types_identical(lhs.type, extra.type)) { + gbString a = type_to_string(lhs.type); + gbString b = type_to_string(extra.type); + error(extra.expr, "'%.*s' expects constant values of the same slice type, got '%s' vs '%s'", LIT(builtin_name), a, b); + gb_string_free(b); + gb_string_free(a); + return false; + } + } else if (is_type_array(lhs.type)) { + if (!is_type_array(extra.type)) { + gbString a = type_to_string(extra.type); + error(extra.expr, "'%.*s' expects a constant array or slice, got %s", LIT(builtin_name), a); + gb_string_free(a); + return false; + } + Type *extra_elem_type = base_array_type(extra.type); + if (!are_types_identical(elem_type, extra_elem_type)) { + gbString a = type_to_string(elem_type); + gbString b = type_to_string(extra_elem_type); + error(extra.expr, "'%.*s' expects constant values of the same element-type, got '%s' vs '%s'", LIT(builtin_name), a, b); + gb_string_free(b); + gb_string_free(a); + return false; + } + } else { + GB_PANIC("Unhandled type: %s", type_to_string(lhs.type)); + } + + if (extra.value.kind != ExactValue_Compound) { + gbString a = exact_value_to_string(extra.value); + error(extra.expr, "Expected a compound literal value for '%.*s', got '%s'", LIT(builtin_name), a); + gb_string_free(a); + return false; + } + + ast_node(extra_cl, CompoundLit, extra.value.value_compound); + + + for (Ast *elem : extra_cl->elems) { + if (elem->kind == Ast_FieldValue) { + error(elem, "'%.*s' does not allow the use of 'field = value' to be concatenated together", LIT(builtin_name)); + return false; + } + } + } + + isize count_needed = 0; + + for (Ast *arg : ce->args) { + ExactValue value = arg->tav.value; + GB_ASSERT(value.kind == ExactValue_Compound); + ast_node(cl, CompoundLit, value.value_compound); + count_needed += cl->elems.count; + } + + Array<Ast *> new_elems = {}; + array_init(&new_elems, permanent_allocator(), 0, count_needed); + + for (Ast *arg : ce->args) { + ExactValue value = arg->tav.value; + GB_ASSERT(value.kind == ExactValue_Compound); + ast_node(cl, CompoundLit, value.value_compound); + array_add_elems(&new_elems, cl->elems.data, cl->elems.count); + } + + Ast *new_compound_lit = ast_compound_lit(lhs.expr->file(), nullptr, new_elems, ast_token(lhs.expr), ast_end_token(ce->args[ce->args.count-1])); + + operand->mode = Addressing_Constant; + operand->value = exact_value_compound(new_compound_lit); + + if (is_type_slice(lhs.type)) { + operand->type = lhs.type; + } else { + operand->type = alloc_type_array(elem_type, new_elems.count); + } + break; + } + case BuiltinProc_alloca: { Operand sz = {}; @@ -6181,7 +6406,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As } Type *new_type = alloc_type_union(); - auto variants = slice_make<Type *>(permanent_allocator(), bt->Union.variants.count); + auto variants = permanent_slice_make<Type *>(bt->Union.variants.count); for_array(i, bt->Union.variants) { variants[i] = alloc_type_pointer(bt->Union.variants[i]); } @@ -6364,6 +6589,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As case BuiltinProc_type_is_boolean: + case BuiltinProc_type_is_bit_field: case BuiltinProc_type_is_integer: case BuiltinProc_type_is_rune: case BuiltinProc_type_is_float: @@ -6371,6 +6597,8 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As case BuiltinProc_type_is_quaternion: case BuiltinProc_type_is_string: case BuiltinProc_type_is_string16: + case BuiltinProc_type_is_cstring: + case BuiltinProc_type_is_cstring16: case BuiltinProc_type_is_typeid: case BuiltinProc_type_is_any: case BuiltinProc_type_is_endian_platform: @@ -6383,8 +6611,8 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As case BuiltinProc_type_is_indexable: case BuiltinProc_type_is_sliceable: case BuiltinProc_type_is_comparable: - case BuiltinProc_type_is_simple_compare: - case BuiltinProc_type_is_nearly_simple_compare: + case BuiltinProc_type_is_simple_compare: // easily compared using memcmp + case BuiltinProc_type_is_nearly_simple_compare: // easily compared using memcmp (including floats) case BuiltinProc_type_is_dereferenceable: case BuiltinProc_type_is_valid_map_key: case BuiltinProc_type_is_valid_matrix_elements: @@ -6401,9 +6629,9 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As case BuiltinProc_type_is_enum: case BuiltinProc_type_is_proc: case BuiltinProc_type_is_bit_set: - case BuiltinProc_type_is_bit_field: case BuiltinProc_type_is_simd_vector: case BuiltinProc_type_is_matrix: + case BuiltinProc_type_is_raw_union: case BuiltinProc_type_is_specialized_polymorphic_record: case BuiltinProc_type_is_unspecialized_polymorphic_record: case BuiltinProc_type_has_nil: @@ -6466,7 +6694,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As check_expr(c, &x, ce->args[1]); if (!is_type_string(x.type) || x.mode != Addressing_Constant || x.value.kind != ExactValue_String) { - error(ce->args[1], "Expected a const string for field argument"); + error(ce->args[1], "Expected a constant string for field argument"); return false; } @@ -6546,7 +6774,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As check_expr(c, &x, ce->args[1]); if (!is_type_string(x.type) || x.mode != Addressing_Constant || x.value.kind != ExactValue_String) { - error(ce->args[1], "Expected a const string for field argument"); + error(ce->args[1], "Expected a constant string for field argument"); return false; } @@ -6683,9 +6911,13 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As // NOTE(jakubtomsu): forces calculation of variant_block_size type_size_of(u); - // NOTE(Jeroen): A tag offset of zero is perfectly fine if all members of the union are empty structs. - // What matters is that the tag size is > 0. - GB_ASSERT(u->Union.tag_size > 0); + if (u->Union.tag_size == 0) { + GB_ASSERT(is_type_union_maybe_pointer(u)); + } else { + // NOTE(Jeroen): A tag offset of zero is perfectly fine if all members of the union are empty structs. + // What matters is that the tag size is > 0. + GB_ASSERT(u->Union.tag_size > 0); + } operand->mode = Addressing_Constant; operand->type = t_untyped_integer; @@ -7166,6 +7398,129 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As operand->type = t_untyped_bool; } break; + case BuiltinProc_type_is_superset_of: + { + Operand op_super = {}; + Operand op_sub = {}; + + check_expr_or_type(c, &op_super, ce->args[0]); + if (op_super.mode != Addressing_Type) { + gbString e = expr_to_string(op_super.expr); + error(op_super.expr, "'%.*s' expects a type, got %s", LIT(builtin_name), e); + gb_string_free(e); + return false; + } + check_expr_or_type(c, &op_sub, ce->args[1]); + if (op_sub.mode != Addressing_Type) { + gbString e = expr_to_string(op_sub.expr); + error(op_sub.expr, "'%.*s' expects a type, got %s", LIT(builtin_name), e); + gb_string_free(e); + return false; + } + + operand->mode = Addressing_Constant; + operand->type = t_untyped_bool; + + Type *super = op_super.type; + Type *sub = op_sub.type; + if (are_types_identical(super, sub)) { + operand->value = exact_value_bool(true); + return true; + } + + super = base_type(super); + sub = base_type(sub); + if (are_types_identical(super, sub)) { + operand->value = exact_value_bool(true); + return true; + } + + if (super->kind != sub->kind) { + gbString a = type_to_string(op_super.type); + gbString b = type_to_string(op_sub.type); + error(op_super.expr, "'%.*s' expects types of the same kind, got %s vs %s", LIT(builtin_name), a, b); + gb_string_free(b); + gb_string_free(a); + return false; + } + + if (super->kind == Type_Enum) { + if (sub->Enum.fields.count > super->Enum.fields.count) { + operand->value = exact_value_bool(false); + return true; + } + + + Type *base_super = base_enum_type(super); + Type *base_sub = base_enum_type(sub); + if (base_super == base_sub && base_super == nullptr) { + // okay + } else if (!are_types_identical(base_type(base_super), base_type(base_sub))) { + operand->value = exact_value_bool(false); + return true; + } + + for (Entity *f_sub : sub->Enum.fields) { + bool found = false; + + if (f_sub->kind != Entity_Constant) { + continue; + } + + for (Entity *f_super : super->Enum.fields) { + if (f_super->kind != Entity_Constant) { + continue; + } + + if (f_sub->token.string == f_super->token.string) { + if (compare_exact_values(Token_CmpEq, f_sub->Constant.value, f_super->Constant.value)) { + found = true; + break; + } + } + } + + if (!found) { + operand->value = exact_value_bool(false); + return true; + } + } + + operand->value = exact_value_bool(true); + return true; + + } else if (super->kind == Type_Union) { + if (sub->Union.variants.count > super->Union.variants.count) { + operand->value = exact_value_bool(false); + return true; + } + if (sub->Union.kind != super->Union.kind) { + operand->value = exact_value_bool(false); + return true; + } + + for_array(i, sub->Union.variants) { + Type *t_sub = sub->Union.variants[i]; + Type *t_super = super->Union.variants[i]; + if (!are_types_identical(t_sub, t_super)) { + operand->value = exact_value_bool(false); + return true; + } + } + + operand->value = exact_value_bool(true); + return true; + + } + gbString a = type_to_string(op_super.type); + gbString b = type_to_string(op_sub.type); + error(op_super.expr, "'%.*s' expects types of the same kind and either an enum or union, got %s vs %s", LIT(builtin_name), a, b); + gb_string_free(b); + gb_string_free(a); + return false; + } + + case BuiltinProc_type_field_index_of: { Operand op = {}; @@ -7179,7 +7534,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As check_expr(c, &x, ce->args[1]); if (!is_type_string(x.type) || x.mode != Addressing_Constant || x.value.kind != ExactValue_String) { - error(ce->args[1], "Expected a const string for field argument"); + error(ce->args[1], "Expected a constant string for field argument"); return false; } diff --git a/src/check_decl.cpp b/src/check_decl.cpp index 7dd9db105..27babd255 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -162,8 +162,6 @@ gb_internal void override_entity_in_scope(Entity *original_entity, Entity *new_e if (found_scope == nullptr) { return; } - rw_mutex_lock(&found_scope->mutex); - defer (rw_mutex_unlock(&found_scope->mutex)); // IMPORTANT NOTE(bill, 2021-04-10): Overriding behaviour was flawed in that the // original entity was still used check checked, but the checking was only @@ -172,7 +170,9 @@ gb_internal void override_entity_in_scope(Entity *original_entity, Entity *new_e // Therefore two things can be done: the type can be assigned to state that it // has been "evaluated" and the variant data can be copied across + rw_mutex_lock(&found_scope->mutex); string_map_set(&found_scope->elements, original_name, new_entity); + rw_mutex_unlock(&found_scope->mutex); original_entity->flags |= EntityFlag_Overridden; original_entity->type = new_entity->type; @@ -559,6 +559,11 @@ gb_internal void check_type_decl(CheckerContext *ctx, Entity *e, Ast *init_expr, Type *super = ac.objc_superclass; while (super != nullptr) { + if (super->kind != Type_Named) { + error(e->token, "@(objc_superclass) Referenced type must be a named struct"); + break; + } + if (type_set_update(&super_set, super)) { error(e->token, "@(objc_superclass) Superclass hierarchy cycle encountered"); break; @@ -566,11 +571,6 @@ gb_internal void check_type_decl(CheckerContext *ctx, Entity *e, Ast *init_expr, check_single_global_entity(ctx->checker, super->Named.type_name, super->Named.type_name->decl_info); - if (super->kind != Type_Named) { - error(e->token, "@(objc_superclass) Referenced type must be a named struct"); - break; - } - Type* named_type = base_named_type(super); GB_ASSERT(named_type->kind == Type_Named); @@ -587,9 +587,7 @@ gb_internal void check_type_decl(CheckerContext *ctx, Entity *e, Ast *init_expr, super = named_type->Named.type_name->TypeName.objc_superclass; } } else { - if (ac.objc_superclass != nullptr) { - error(e->token, "@(objc_superclass) may only be applied when the @(obj_implement) attribute is also applied"); - } else if (ac.objc_ivar != nullptr) { + if (ac.objc_ivar != nullptr) { error(e->token, "@(objc_ivar) may only be applied when the @(obj_implement) attribute is also applied"); } else if (ac.objc_context_provider != nullptr) { error(e->token, "@(objc_context_provider) may only be applied when the @(obj_implement) attribute is also applied"); @@ -851,6 +849,50 @@ gb_internal bool signature_parameter_similar_enough(Type *x, Type *y) { } } + Type *x_base = base_type(x); + Type *y_base = base_type(y); + + if (x_base == y_base) { + return true; + } + + if (x_base->kind == y_base->kind && + x_base->kind == Type_Struct) { + i64 xs = type_size_of(x_base); + i64 ys = type_size_of(y_base); + + i64 xa = type_align_of(x_base); + i64 ya = type_align_of(y_base); + + + if (x_base->Struct.is_raw_union == y_base->Struct.is_raw_union && + xs == ys && xa == ya) { + if (xs > 16) { + // @@ABI NOTE(bill): Just allow anything over 16-bytes to be allowed, because on all current ABIs + // it will be passed by point + // NOTE(bill): this must be changed when ABI changes + return true; + } + if (x_base->Struct.is_raw_union) { + return true; + } + if (x->Struct.fields.count == y->Struct.fields.count) { + for (isize i = 0; i < x->Struct.fields.count; i++) { + Entity *a = x->Struct.fields[i]; + Entity *b = y->Struct.fields[i]; + bool similar = signature_parameter_similar_enough(a->type, b->type); + if (!similar) { + // NOTE(bill): If the fields are not similar enough, then stop. + goto end; + } + } + } + // HACK NOTE(bill): Allow this for the time begin until it actually becomes a practical problem + return true; + } + } + +end:; return are_types_identical(x, y); } @@ -948,7 +990,7 @@ gb_internal Entity *init_entity_foreign_library(CheckerContext *ctx, Entity *e) error(ident, "foreign library names must be an identifier"); } else { String name = ident->Ident.token.string; - Entity *found = scope_lookup(ctx->scope, name); + Entity *found = scope_lookup(ctx->scope, name, ident->Ident.hash); if (found == nullptr) { if (is_blank_ident(name)) { @@ -1040,61 +1082,100 @@ gb_internal void check_objc_methods(CheckerContext *ctx, Entity *e, AttributeCon // Enable implementation by default if the class is an implementer too and // @objc_implement was not set to false explicitly in this proc. bool implement = tn->TypeName.objc_is_implementation; + if( ac.objc_is_implementation && !tn->TypeName.objc_is_implementation ) { + error(e->token, "Cannot apply @(objc_is_implement) to a procedure whose type does not also have @(objc_is_implement) set"); + } + if (ac.objc_is_disabled_implement) { implement = false; } - if (implement) { - GB_ASSERT(e->kind == Entity_Procedure); + String objc_selector = ac.objc_selector != "" ? ac.objc_selector : ac.objc_name; + + if (e->kind == Entity_Procedure) { + bool has_body = e->decl_info->proc_lit->ProcLit.body != nullptr; + e->Procedure.is_objc_impl_or_import = implement || !has_body; + e->Procedure.is_objc_class_method = ac.objc_is_class_method; + e->Procedure.objc_selector_name = objc_selector; + e->Procedure.objc_class = tn; auto &proc = e->type->Proc; Type *first_param = proc.param_count > 0 ? proc.params->Tuple.variables[0]->type : t_untyped_nil; - if (!tn->TypeName.objc_is_implementation) { - error(e->token, "@(objc_is_implement) attribute may only be applied to procedures whose class also have @(objc_is_implement) applied"); - } else if (!ac.objc_is_class_method && !(first_param->kind == Type_Pointer && internal_check_is_assignable_to(t, first_param->Pointer.elem))) { - error(e->token, "Objective-C instance methods implementations require the first parameter to be a pointer to the class type set by @(objc_type)"); - } else if (proc.calling_convention == ProcCC_Odin && !tn->TypeName.objc_context_provider) { - error(e->token, "Objective-C methods with Odin calling convention can only be used with classes that have @(objc_context_provider) set"); - } else if (ac.objc_is_class_method && proc.calling_convention != ProcCC_CDecl) { - error(e->token, "Objective-C class methods (objc_is_class_method=true) that have @objc_is_implementation can only use \"c\" calling convention"); - } else if (proc.result_count > 1) { - error(e->token, "Objective-C method implementations may return at most 1 value"); - } else { - // Always export unconditionally - // NOTE(harold): This means check_objc_methods() MUST be called before - // e->Procedure.is_export is set in check_proc_decl()! - if (ac.is_export) { - error(e->token, "Explicit export not allowed when @(objc_implement) is set. It set exported implicitly"); - } - if (ac.link_name != "") { - error(e->token, "Explicit linkage not allowed when @(objc_implement) is set. It set to \"strong\" implicitly"); - } + if (implement) { + if( !has_body ) { + error(e->token, "Procedures with @(objc_is_implement) must have a body"); + } else if (!tn->TypeName.objc_is_implementation) { + error(e->token, "@(objc_is_implement) attribute may only be applied to procedures whose class also have @(objc_is_implement) applied"); + } else if (!ac.objc_is_class_method && !(first_param->kind == Type_Pointer && internal_check_is_assignable_to(t, first_param->Pointer.elem))) { + error(e->token, "Objective-C instance methods implementations require the first parameter to be a pointer to the class type set by @(objc_type)"); + } else if (proc.calling_convention == ProcCC_Odin && !tn->TypeName.objc_context_provider) { + error(e->token, "Objective-C methods with Odin calling convention can only be used with classes that have @(objc_context_provider) set"); + } else if (ac.objc_is_class_method && proc.calling_convention != ProcCC_CDecl) { + error(e->token, "Objective-C class methods (objc_is_class_method=true) that have @objc_is_implementation can only use \"c\" calling convention"); + } else if (proc.result_count > 1) { + error(e->token, "Objective-C method implementations may return at most 1 value"); + } else { + // Always export unconditionally + // NOTE(harold): This means check_objc_methods() MUST be called before + // e->Procedure.is_export is set in check_proc_decl()! + if (ac.is_export) { + error(e->token, "Explicit export not allowed when @(objc_implement) is set. It set exported implicitly"); + } + if (ac.link_name != "") { + error(e->token, "Explicit linkage not allowed when @(objc_implement) is set. It set to \"strong\" implicitly"); + } - ac.is_export = true; - ac.linkage = STR_LIT("strong"); + ac.is_export = true; + ac.linkage = STR_LIT("strong"); - auto method = ObjcMethodData{ ac, e }; - method.ac.objc_selector = ac.objc_selector != "" ? ac.objc_selector : ac.objc_name; + auto method = ObjcMethodData{ ac, e }; + method.ac.objc_selector = objc_selector; - CheckerInfo *info = ctx->info; - mutex_lock(&info->objc_method_mutex); - defer (mutex_unlock(&info->objc_method_mutex)); + CheckerInfo *info = ctx->info; + mutex_lock(&info->objc_method_mutex); + defer (mutex_unlock(&info->objc_method_mutex)); - Array<ObjcMethodData>* method_list = map_get(&info->objc_method_implementations, t); - if (method_list) { - array_add(method_list, method); - } else { - auto list = array_make<ObjcMethodData>(permanent_allocator(), 1, 8); - list[0] = method; + Array<ObjcMethodData>* method_list = map_get(&info->objc_method_implementations, t); + if (method_list) { + array_add(method_list, method); + } else { + auto list = array_make<ObjcMethodData>(permanent_allocator(), 1, 8); + list[0] = method; - map_set(&info->objc_method_implementations, t, list); + map_set(&info->objc_method_implementations, t, list); + } + } + } else if (!has_body) { + if (ac.objc_selector == "The @(objc_selector) attribute is required for imported Objective-C methods.") { + return; + } else if (proc.calling_convention != ProcCC_CDecl) { + error(e->token, "Imported Objective-C methods must use the \"c\" calling convention"); + return; + } else if (tn->TypeName.objc_context_provider) { + error(e->token, "Imported Objective-C class '%.*s' must not declare context providers.", tn->type->Named.name); + return; + } else if (tn->TypeName.objc_is_implementation) { + error(e->token, "Imported Objective-C methods used in a class with @(objc_implement) is not allowed."); + return; + } else if (!ac.objc_is_class_method && !(first_param->kind == Type_Pointer && internal_check_is_assignable_to(t, first_param->Pointer.elem))) { + error(e->token, "Objective-C instance methods require the first parameter to be a pointer to the class type set by @(objc_type)"); + return; } } - } else if (ac.objc_selector != "") { - error(e->token, "@(objc_selector) may only be applied to procedures that are Objective-C implementations."); + else if(ac.objc_selector != "") { + error(e->token, "@(objc_selector) may only be applied to procedures that are Objective-C method implementations or are imported."); + return; + } + } else { + GB_ASSERT(e->kind == Entity_ProcGroup); + if (tn->TypeName.objc_is_implementation) { + error(e->token, "Objective-C procedure groups cannot use the @(objc_implement) attribute."); + return; + } } + mutex_lock(&global_type_name_objc_metadata_mutex); defer (mutex_unlock(&global_type_name_objc_metadata_mutex)); @@ -1479,7 +1560,7 @@ gb_internal void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) { if (!pt->is_polymorphic) { check_procedure_later(ctx->checker, ctx->file, e->token, d, proc_type, pl->body, pl->tags); } - } else if (!is_foreign) { + } else if (!is_foreign && !e->Procedure.is_objc_impl_or_import) { if (e->Procedure.is_export) { error(e->token, "Foreign export procedures must have a body"); } else { @@ -1526,7 +1607,7 @@ gb_internal void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) { if (is_arch_wasm() && foreign_library != nullptr) { // NOTE(bill): this must be delayed because the foreign import paths might not be evaluated yet until much later mpsc_enqueue(&ctx->info->foreign_decls_to_check, e); - } else { + } else if (!e->Procedure.is_objc_impl_or_import) { check_foreign_procedure(ctx, e, d); } } else { @@ -1549,7 +1630,7 @@ gb_internal void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) { "\tother at %s", LIT(name), token_pos_to_string(pos)); } else if (name == "main") { - if (d->entity->pkg->kind != Package_Runtime) { + if (d->entity.load()->pkg->kind != Package_Runtime) { error(d->proc_lit, "The link name 'main' is reserved for internal use"); } } else { @@ -1565,7 +1646,7 @@ gb_internal void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) { } } -gb_internal void check_global_variable_decl(CheckerContext *ctx, Entity *&e, Ast *type_expr, Ast *init_expr) { +gb_internal void check_global_variable_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Ast *init_expr) { GB_ASSERT(e->type == nullptr); GB_ASSERT(e->kind == Entity_Variable); @@ -1686,7 +1767,28 @@ gb_internal void check_global_variable_decl(CheckerContext *ctx, Entity *&e, Ast check_expr_with_type_hint(ctx, &o, init_expr, e->type); check_init_variable(ctx, e, &o, str_lit("variable declaration")); if (e->Variable.is_rodata && o.mode != Addressing_Constant) { + ERROR_BLOCK(); error(o.expr, "Variables declared with @(rodata) must have constant initialization"); + Ast *expr = unparen_expr(o.expr); + if (is_type_struct(e->type) && expr && expr->kind == Ast_CompoundLit) { + ast_node(cl, CompoundLit, expr); + for (Ast *elem_ : cl->elems) { + Ast *elem = elem_; + if (elem->kind == Ast_FieldValue) { + elem = elem->FieldValue.value; + } + elem = unparen_expr(elem); + + Entity *e = entity_of_node(elem); + if (elem->tav.mode != Addressing_Constant && e == nullptr && elem->kind != Ast_ProcLit) { + Token tok = ast_token(elem); + TokenPos pos = tok.pos; + gbString s = type_to_string(type_of_expr(elem)); + error_line("%s Element is not constant, which is required for @(rodata), of type %s\n", token_pos_to_string(pos), s); + gb_string_free(s); + } + } + } } check_rtti_type_disallowed(e->token, e->type, "A variable declaration is using a type, %s, which has been disallowed"); @@ -1915,7 +2017,7 @@ gb_internal void add_deps_from_child_to_parent(DeclInfo *decl) { rw_mutex_shared_lock(&decl->deps_mutex); rw_mutex_lock(&decl->parent->deps_mutex); - for (Entity *e : decl->deps) { + FOR_PTR_SET(e, decl->deps) { ptr_set_add(&decl->parent->deps, e); } @@ -1967,8 +2069,8 @@ gb_internal bool check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *de ctx->curr_proc_sig = type; ctx->curr_proc_calling_convention = type->Proc.calling_convention; - if (decl->parent && decl->entity && decl->parent->entity) { - decl->entity->parent_proc_decl = decl->parent; + if (decl->parent && decl->entity.load() && decl->parent->entity) { + decl->entity.load()->parent_proc_decl = decl->parent; } if (ctx->pkg->name != "runtime") { @@ -1981,9 +2083,9 @@ gb_internal bool check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *de ast_node(bs, BlockStmt, body); + TEMPORARY_ALLOCATOR_GUARD(); Array<ProcUsingVar> using_entities = {}; - using_entities.allocator = heap_allocator(); - defer (array_free(&using_entities)); + using_entities.allocator = temporary_allocator(); { if (type->Proc.param_count > 0) { @@ -2072,7 +2174,7 @@ gb_internal bool check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *de GB_ASSERT(decl->proc_checked_state != ProcCheckedState_Checked); if (decl->defer_use_checked) { GB_ASSERT(is_type_polymorphic(type, true)); - error(token, "Defer Use Checked: %.*s", LIT(decl->entity->token.string)); + error(token, "Defer Use Checked: %.*s", LIT(decl->entity.load()->token.string)); GB_ASSERT(decl->defer_use_checked == false); } diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 542a2afa1..2fe6c0251 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -587,6 +587,7 @@ gb_internal bool find_or_generate_polymorphic_procedure(CheckerContext *old_c, E d->proc_lit = proc_lit; d->proc_checked_state = ProcCheckedState_Unchecked; d->defer_use_checked = false; + d->para_poly_original = old_decl->entity; Entity *entity = alloc_entity_procedure(nullptr, token, final_proc_type, tags); entity->state.store(EntityState_Resolved); @@ -608,7 +609,7 @@ gb_internal bool find_or_generate_polymorphic_procedure(CheckerContext *old_c, E entity->flags |= EntityFlag_Disabled; } - d->entity = entity; + d->entity.store(entity); AstFile *file = nullptr; { @@ -821,9 +822,11 @@ gb_internal i64 check_distance_between_types(CheckerContext *c, Operand *operand } } - if (is_type_enum(dst) && are_types_identical(dst->Enum.base_type, operand->type)) { - if (c->in_enum_type) { - return 3; + if (c != nullptr) { + if (is_type_enum(dst) && are_types_identical(dst->Enum.base_type, operand->type)) { + if (c->in_enum_type) { + return 3; + } } } @@ -1738,7 +1741,7 @@ gb_internal Entity *check_ident(CheckerContext *c, Operand *o, Ast *n, Type *nam o->expr = n; String name = n->Ident.token.string; - Entity *e = scope_lookup(c->scope, name); + Entity *e = scope_lookup(c->scope, name, n->Ident.hash); if (e == nullptr) { if (is_blank_ident(name)) { error(n, "'_' cannot be used as a value"); @@ -2113,9 +2116,6 @@ gb_internal bool check_representable_as_constant(CheckerContext *c, ExactValue i } return in_value.kind == ExactValue_String; } else if (is_type_integer(type) || is_type_rune(type)) { - if (in_value.kind == ExactValue_Bool) { - return false; - } ExactValue v = exact_value_to_integer(in_value); if (v.kind != ExactValue_Integer) { return false; @@ -2333,6 +2333,20 @@ gb_internal bool check_representable_as_constant(CheckerContext *c, ExactValue i if (in_value.kind == ExactValue_Integer) { return true; } + } else if (is_type_typeid(type)) { + + if (in_value.kind == ExactValue_Compound) { + ast_node(cl, CompoundLit, in_value.value_compound); + if (cl->elems.count == 0) { + in_value = exact_value_typeid(nullptr); + } else { + return false; + } + } + if (in_value.kind == ExactValue_Typeid) { + if (out_value) *out_value = in_value; + return true; + } } return false; @@ -3222,6 +3236,9 @@ gb_internal void check_shift(CheckerContext *c, Operand *x, Operand *y, Ast *nod } gb_internal bool check_is_castable_to(CheckerContext *c, Operand *operand, Type *y) { + if (are_types_identical(operand->type, y)) { + return true; + } if (check_is_assignable_to(c, operand, y)) { return true; } @@ -3503,27 +3520,42 @@ gb_internal bool check_is_castable_to(CheckerContext *c, Operand *operand, Type gb_internal bool check_cast_internal(CheckerContext *c, Operand *x, Type *type) { bool is_const_expr = x->mode == Addressing_Constant; + Type *bt = base_type(type); if (is_const_expr && is_type_constant_type(bt)) { + Type *elem = core_array_type(bt); + if (core_type(bt)->kind == Type_Basic) { - if (check_representable_as_constant(c, x->value, bt, &x->value)) { + if (check_representable_as_constant(c, x->value, type, &x->value)) { + return true; + } + goto check_castable; + } else if (!are_types_identical(elem, bt) && + elem->kind == Type_Basic && + check_representable_as_constant(c, x->value, elem, &x->value)) { + if (check_representable_as_constant(c, x->value, type, &x->value)) { return true; - } else if (check_is_castable_to(c, x, type)) { - if (is_type_pointer(type)) { - return true; - } } + goto check_castable; } else if (check_is_castable_to(c, x, type)) { x->value = {}; x->mode = Addressing_Value; return true; } - } else if (check_is_castable_to(c, x, type)) { + + return false; + } + +check_castable: + if (check_is_castable_to(c, x, type)) { if (x->mode != Addressing_Constant) { x->mode = Addressing_Value; } else if (is_type_slice(type) && is_type_string(x->type)) { x->mode = Addressing_Value; } else if (is_type_union(type)) { + if (is_type_union_constantable(type)) { + return true; + } x->mode = Addressing_Value; } if (x->mode == Addressing_Value) { @@ -4137,7 +4169,7 @@ gb_internal void check_binary_expr(CheckerContext *c, Operand *x, Ast *node, Typ default: if (is_ise_expr(be->left)) { // Evalute the right before the left for an '.X' expression - check_expr_or_type(c, y, be->right, type_hint); + check_expr_or_type(c, y, be->right, token_is_comparison(op.kind) ? nullptr : type_hint); if (can_use_other_type_as_type_hint(use_lhs_as_type_hint, y->type)) { // RHS in this case check_expr_or_type(c, x, be->left, y->type); @@ -4149,7 +4181,7 @@ gb_internal void check_binary_expr(CheckerContext *c, Operand *x, Ast *node, Typ if (can_use_other_type_as_type_hint(use_lhs_as_type_hint, x->type)) { check_expr_with_type_hint(c, y, be->right, x->type); } else { - check_expr_with_type_hint(c, y, be->right, type_hint); + check_expr_with_type_hint(c, y, be->right, token_is_comparison(op.kind) ? nullptr : type_hint); } } break; @@ -4419,6 +4451,9 @@ gb_internal void check_binary_expr(CheckerContext *c, Operand *x, Ast *node, Typ break; } } + } else if (is_type_array_like(x->type)) { + x->mode = Addressing_Value; + return; } else { x->value = exact_binary_operator_value(op.kind, a, b); } @@ -4639,7 +4674,6 @@ gb_internal ExactValue convert_exact_value_for_type(ExactValue v, Type *type) { } gb_internal void convert_to_typed(CheckerContext *c, Operand *operand, Type *target_type) { - // GB_ASSERT_NOT_NULL(target_type); if (target_type == nullptr || operand->mode == Addressing_Invalid || operand->mode == Addressing_Type || is_type_typed(operand->type) || @@ -4810,7 +4844,7 @@ gb_internal void convert_to_typed(CheckerContext *c, Operand *operand, Type *tar TEMPORARY_ALLOCATOR_GUARD(); isize count = t->Union.variants.count; - ValidIndexAndScore *valids = gb_alloc_array(temporary_allocator(), ValidIndexAndScore, count); + ValidIndexAndScore *valids = temporary_alloc_array<ValidIndexAndScore>(count); isize valid_count = 0; isize first_success_index = -1; for_array(i, t->Union.variants) { @@ -4851,7 +4885,10 @@ gb_internal void convert_to_typed(CheckerContext *c, Operand *operand, Type *tar break; } operand->type = new_type; - operand->mode = Addressing_Value; + if (operand->mode != Addressing_Constant || + !elem_type_can_be_constant(operand->type)) { + operand->mode = Addressing_Value; + } break; } else if (valid_count > 1) { ERROR_BLOCK(); @@ -5093,7 +5130,11 @@ gb_internal ExactValue get_constant_field_single(CheckerContext *c, ExactValue v } if (cl->elems[0]->kind == Ast_FieldValue) { - if (is_type_struct(node->tav.type)) { + if (is_type_raw_union(node->tav.type)) { + if (success_) *success_ = false; + if (finish_) *finish_ = true; + return empty_exact_value; + } else if (is_type_struct(node->tav.type)) { bool found = false; for (Ast *elem : cl->elems) { if (elem->kind != Ast_FieldValue) { @@ -5102,7 +5143,6 @@ gb_internal ExactValue get_constant_field_single(CheckerContext *c, ExactValue v ast_node(fv, FieldValue, elem); String name = fv->field->Ident.token.string; Selection sub_sel = lookup_field(node->tav.type, name, false); - defer (array_free(&sub_sel.index)); if (sub_sel.index.count > 0 && sub_sel.index[0] == index) { value = fv->value->tav.value; @@ -5363,7 +5403,7 @@ gb_internal Entity *check_entity_from_ident_or_selector(CheckerContext *c, Ast * } } else */if (node->kind == Ast_Ident) { String name = node->Ident.token.string; - return scope_lookup(c->scope, name); + return scope_lookup(c->scope, name, node->Ident.hash); } else if (!ident_only) if (node->kind == Ast_SelectorExpr) { ast_node(se, SelectorExpr, node); if (se->token.kind == Token_ArrowRight) { @@ -5385,7 +5425,7 @@ gb_internal Entity *check_entity_from_ident_or_selector(CheckerContext *c, Ast * if (op_expr->kind == Ast_Ident) { String op_name = op_expr->Ident.token.string; - Entity *e = scope_lookup(c->scope, op_name); + Entity *e = scope_lookup(c->scope, op_name, op_expr->Ident.hash); if (e == nullptr) { return nullptr; } @@ -5482,7 +5522,7 @@ gb_internal Entity *check_selector(CheckerContext *c, Operand *operand, Ast *nod if (op_expr->kind == Ast_Ident) { String op_name = op_expr->Ident.token.string; - Entity *e = scope_lookup(c->scope, op_name); + Entity *e = scope_lookup(c->scope, op_name, op_expr->Ident.hash); add_entity_use(c, op_expr, e); expr_entity = e; @@ -5808,7 +5848,7 @@ gb_internal Entity *check_selector(CheckerContext *c, Operand *operand, Ast *nod switch (entity->kind) { case Entity_Constant: - operand->value = entity->Constant.value; + operand->value = entity->Constant.value; operand->mode = Addressing_Constant; if (operand->value.kind == ExactValue_Procedure) { Entity *proc = strip_entity_wrapping(operand->value.value_procedure); @@ -5905,7 +5945,7 @@ gb_internal bool check_identifier_exists(Scope *s, Ast *node, bool nested = fals return true; } } else { - Entity *e = scope_lookup(s, name); + Entity *e = scope_lookup(s, name, i->hash); if (e != nullptr) { if (out_scope) *out_scope = e->scope; return true; @@ -6029,7 +6069,7 @@ gb_internal bool check_unpack_arguments(CheckerContext *ctx, Entity **lhs, isize } rw_mutex_shared_lock(&decl->deps_mutex); rw_mutex_lock(&c->decl->deps_mutex); - for (Entity *dep : decl->deps) { + FOR_PTR_SET(dep, decl->deps) { ptr_set_add(&c->decl->deps, dep); } rw_mutex_unlock(&c->decl->deps_mutex); @@ -6185,7 +6225,6 @@ gb_internal isize get_procedure_param_count_excluding_defaults(Type *pt, isize * continue; } } - break; } } @@ -6257,7 +6296,7 @@ gb_internal CallArgumentError check_call_arguments_internal(CheckerContext *c, A } GB_ASSERT(ce->split_args); - auto visited = slice_make<bool>(temporary_allocator(), pt->param_count); + auto visited = temporary_slice_make<bool>(pt->param_count); auto ordered_operands = array_make<Operand>(temporary_allocator(), pt->param_count); defer ({ for (Operand const &o : ordered_operands) { @@ -6473,7 +6512,14 @@ gb_internal CallArgumentError check_call_arguments_internal(CheckerContext *c, A } if (e && e->kind == Entity_Constant && is_type_proc(e->type)) { - if (o->mode != Addressing_Constant) { + bool ok = false; + if (o->mode == Addressing_Constant) { + ok = true; + } else if (o->value.kind == ExactValue_Procedure) { + ok = true; + } + + if (!ok) { if (show_error) { error(o->expr, "Expected a constant procedure value for the argument '%.*s'", LIT(e->token.string)); } @@ -6972,6 +7018,10 @@ gb_internal CallArgumentData check_call_arguments_proc_group(CheckerContext *c, array_unordered_remove(&procs, proc_index); continue; } + if (!pt->Proc.variadic && max_arg_count != ISIZE_MAX && param_count < max_arg_count) { + array_unordered_remove(&procs, proc_index); + continue; + } proc_index++; } } @@ -6980,10 +7030,10 @@ gb_internal CallArgumentData check_call_arguments_proc_group(CheckerContext *c, isize lhs_count = -1; i32 variadic_index = -1; - auto positional_operands = array_make<Operand>(heap_allocator(), 0, 0); - auto named_operands = array_make<Operand>(heap_allocator(), 0, 0); - defer (array_free(&positional_operands)); - defer (array_free(&named_operands)); + TEMPORARY_ALLOCATOR_GUARD(); + + auto positional_operands = array_make<Operand>(temporary_allocator(), 0, 0); + auto named_operands = array_make<Operand>(temporary_allocator(), 0, 0); if (procs.count == 1) { Entity *e = procs[0]; @@ -7024,7 +7074,7 @@ gb_internal CallArgumentData check_call_arguments_proc_group(CheckerContext *c, if (proc_arg_count >= 0) { lhs_count = proc_arg_count; if (lhs_count > 0) { - lhs = gb_alloc_array(heap_allocator(), Entity *, lhs_count); + lhs = gb_alloc_array(temporary_allocator(), Entity *, lhs_count); for (isize param_index = 0; param_index < lhs_count; param_index++) { Entity *e = nullptr; for (Entity *p : procs) { @@ -7110,13 +7160,9 @@ gb_internal CallArgumentData check_call_arguments_proc_group(CheckerContext *c, array_add(&named_operands, o); } - gb_free(heap_allocator(), lhs); - - auto valids = array_make<ValidIndexAndScore>(heap_allocator(), 0, procs.count); - defer (array_free(&valids)); + auto valids = array_make<ValidIndexAndScore>(temporary_allocator(), 0, procs.count); - auto proc_entities = array_make<Entity *>(heap_allocator(), 0, procs.count*2 + 1); - defer (array_free(&proc_entities)); + auto proc_entities = array_make<Entity *>(temporary_allocator(), 0, procs.count*2 + 1); for (Entity *proc : procs) { array_add(&proc_entities, proc); } @@ -7247,7 +7293,7 @@ gb_internal CallArgumentData check_call_arguments_proc_group(CheckerContext *c, } // Try to reduce the list further for `$T: typeid` like parameters - bool *possibly_ignore = gb_alloc_array(temporary_allocator(), bool, procs.count); + bool *possibly_ignore = temporary_alloc_array<bool>(procs.count); isize possibly_ignore_set = 0; if (true) { @@ -7335,7 +7381,7 @@ gb_internal CallArgumentData check_call_arguments_proc_group(CheckerContext *c, } isize max_spaces = gb_max(max_name_length, max_type_length); - char *spaces = gb_alloc_array(temporary_allocator(), char, max_spaces+1); + char *spaces = temporary_alloc_array<char>(max_spaces+1); for (isize i = 0; i < max_spaces; i++) { spaces[i] = ' '; } @@ -7450,8 +7496,6 @@ gb_internal CallArgumentData check_call_arguments_proc_group(CheckerContext *c, Entity *e = proc_entities[valids[0].index]; GB_ASSERT(e != nullptr); - Array<Operand> named_operands = {}; - check_call_arguments_single(c, call, operand, e, e->type, positional_operands, named_operands, @@ -7510,11 +7554,10 @@ gb_internal CallArgumentData check_call_arguments(CheckerContext *c, Operand *op return check_call_arguments_proc_group(c, operand, call); } - auto positional_operands = array_make<Operand>(heap_allocator(), 0, positional_args.count); - auto named_operands = array_make<Operand>(heap_allocator(), 0, 0); + TEMPORARY_ALLOCATOR_GUARD(); - defer (array_free(&positional_operands)); - defer (array_free(&named_operands)); + auto positional_operands = array_make<Operand>(temporary_allocator(), 0, positional_args.count); + auto named_operands = array_make<Operand>(temporary_allocator(), 0, 0); if (positional_args.count > 0) { Entity **lhs = nullptr; @@ -7601,6 +7644,8 @@ gb_internal isize lookup_polymorphic_record_parameter(Type *t, String parameter_ gb_internal CallArgumentError check_polymorphic_record_type(CheckerContext *c, Operand *operand, Ast *call) { + TEMPORARY_ALLOCATOR_GUARD(); + ast_node(ce, CallExpr, call); Type *original_type = operand->type; @@ -7609,7 +7654,6 @@ gb_internal CallArgumentError check_polymorphic_record_type(CheckerContext *c, O bool show_error = true; Array<Operand> operands = {}; - defer (array_free(&operands)); CallArgumentError err = CallArgumentError_None; @@ -7617,15 +7661,14 @@ gb_internal CallArgumentError check_polymorphic_record_type(CheckerContext *c, O { // NOTE(bill, 2019-10-26): Allow a cycle in the parameters but not in the fields themselves auto prev_type_path = c->type_path; - c->type_path = new_checker_type_path(); - defer ({ - destroy_checker_type_path(c->type_path); - c->type_path = prev_type_path; - }); + TEMPORARY_ALLOCATOR_GUARD(); + + c->type_path = new_checker_type_path(temporary_allocator()); + defer (c->type_path = prev_type_path); if (is_call_expr_field_value(ce)) { named_fields = true; - operands = array_make<Operand>(heap_allocator(), ce->args.count); + operands = array_make<Operand>(temporary_allocator(), ce->args.count); for_array(i, ce->args) { Ast *arg = ce->args[i]; ast_node(fv, FieldValue, arg); @@ -7657,7 +7700,7 @@ gb_internal CallArgumentError check_polymorphic_record_type(CheckerContext *c, O } } else { - operands = array_make<Operand>(heap_allocator(), 0, 2*ce->args.count); + operands = array_make<Operand>(temporary_allocator(), 0, 2*ce->args.count); Entity **lhs = nullptr; isize lhs_count = -1; @@ -7699,7 +7742,7 @@ gb_internal CallArgumentError check_polymorphic_record_type(CheckerContext *c, O } else { TEMPORARY_ALLOCATOR_GUARD(); - bool *visited = gb_alloc_array(temporary_allocator(), bool, param_count); + bool *visited = temporary_alloc_array<bool>(param_count); // LEAK(bill) ordered_operands = array_make<Operand>(permanent_allocator(), param_count); @@ -7883,11 +7926,10 @@ gb_internal CallArgumentError check_polymorphic_record_type(CheckerContext *c, O { GenTypesData *found_gen_types = ensure_polymorphic_record_entity_has_gen_types(c, original_type); - mutex_lock(&found_gen_types->mutex); defer (mutex_unlock(&found_gen_types->mutex)); - Entity *found_entity = find_polymorphic_record_entity(found_gen_types, param_count, ordered_operands); + Entity *found_entity = find_polymorphic_record_entity(found_gen_types, param_count, ordered_operands); if (found_entity) { operand->mode = Addressing_Type; operand->type = found_entity->type; @@ -8015,6 +8057,174 @@ gb_internal bool check_call_parameter_mixture(Slice<Ast *> const &args, char con return Expr_Stmt; \ } +gb_internal ExprKind check_call_expr_as_type_cast(CheckerContext *c, Operand *operand, Ast *call, Slice<Ast *> const &args, Type *type_hint) { + GB_ASSERT(operand->mode == Addressing_Type); + Type *t = operand->type; + if (is_type_polymorphic_record(t)) { + CHECK_CALL_PARAMETER_MIXTURE_OR_RETURN("polymorphic type construction"); + + if (!is_type_named(t)) { + gbString s = expr_to_string(operand->expr); + error(call, "Illegal use of an unnamed polymorphic record, %s", s); + gb_string_free(s); + operand->mode = Addressing_Invalid; + operand->type = t_invalid;; + return Expr_Expr; + } + auto err = check_polymorphic_record_type(c, operand, call); + if (err == 0) { + Ast *ident = operand->expr; + while (ident->kind == Ast_SelectorExpr) { + Ast *s = ident->SelectorExpr.selector; + ident = s; + } + Type *ot = operand->type; + GB_ASSERT(ot->kind == Type_Named); + Entity *e = ot->Named.type_name; + add_entity_use(c, ident, e); + add_type_and_value(c, call, Addressing_Type, ot, empty_exact_value); + } else { + operand->mode = Addressing_Invalid; + operand->type = t_invalid; + } + } else { + CHECK_CALL_PARAMETER_MIXTURE_OR_RETURN("type conversion"); + + operand->mode = Addressing_Invalid; + isize arg_count = args.count; + switch (arg_count) { + case 0: + { + gbString str = type_to_string(t); + error(call, "Missing argument in conversion to '%s'", str); + gb_string_free(str); + } break; + default: + { + gbString str = type_to_string(t); + if (t->kind == Type_Basic) { + ERROR_BLOCK(); + switch (t->Basic.kind) { + case Basic_complex32: + case Basic_complex64: + case Basic_complex128: + error(call, "Too many arguments in conversion to '%s'", str); + error_line("\tSuggestion: %s(1+2i) or construct with 'complex'\n", str); + break; + case Basic_quaternion64: + case Basic_quaternion128: + case Basic_quaternion256: + error(call, "Too many arguments in conversion to '%s'", str); + error_line("\tSuggestion: %s(1+2i+3j+4k) or construct with 'quaternion'\n", str); + break; + default: + error(call, "Too many arguments in conversion to '%s'", str); + } + } else { + error(call, "Too many arguments in conversion to '%s'", str); + } + gb_string_free(str); + } break; + case 1: { + Ast *arg = args[0]; + if (arg->kind == Ast_FieldValue) { + error(call, "'field = value' cannot be used in a type conversion"); + arg = arg->FieldValue.value; + // NOTE(bill): Carry on the cast regardless + } + check_expr_with_type_hint(c, operand, arg, t); + if (operand->mode != Addressing_Invalid) { + if (is_type_polymorphic(t)) { + error(call, "A polymorphic type cannot be used in a type conversion"); + } else { + // NOTE(bill): Otherwise the compiler can override the polymorphic type + // as it assumes it is determining the type + check_cast(c, operand, t); + } + } + operand->type = t; + operand->expr = call; + + + if (operand->mode != Addressing_Invalid) { + update_untyped_expr_type(c, arg, t, false); + check_representable_as_constant(c, operand->value, t, &operand->value); + } + break; + } + } + } + return Expr_Expr; +} + + +void add_objc_proc_type(CheckerContext *c, Ast *call, Type *return_type, Slice<Type *> param_types); + +gb_internal void check_objc_call_expr(CheckerContext *c, Operand *operand, Ast *call, Entity *proc_entity, Type *proc_type) { + auto &proc = proc_type->Proc; + Slice<Entity *> params = proc.params ? proc.params->Tuple.variables : Slice<Entity *>{}; + + Type *self_type = nullptr; + isize params_start = 1; + + ast_node(ce, CallExpr, call); + + Type *return_type = proc.result_count == 0 ? nullptr : proc.results->Tuple.variables[0]->type; + bool is_return_instancetype = return_type != nullptr && return_type == t_objc_instancetype; + + if (params.count == 0 || !is_type_objc_ptr_to_object(params[0]->type)) { + if (!proc_entity->Procedure.is_objc_class_method) { + // Not a class method, invalid call + error(call, "Invalid Objective-C call: The Objective-C method is not a class method but this first parameter is not an Objective-C object pointer."); + return; + } + + if (is_return_instancetype) { + if (ce->proc->kind == Ast_SelectorExpr) { + ast_node(se, SelectorExpr, ce->proc); + + // NOTE(harold): These should have already been checked, right? + GB_ASSERT(se->expr->tav.mode == Addressing_Type && se->expr->tav.type->kind == Type_Named); + + return_type = alloc_type_pointer(se->expr->tav.type); + } else { + return_type = proc_entity->Procedure.objc_class->type; + } + } + + self_type = t_objc_Class; + params_start = 0; + } else if (ce->args.count > 0) { + GB_ASSERT(is_type_objc_ptr_to_object(params[0]->type)); + + if (ce->args[0]->tav.objc_super_target) { + self_type = t_objc_super_ptr; + } else { + self_type = ce->args[0]->tav.type; + } + + if (is_return_instancetype) { + // NOTE(harold): These should have already been checked, right? + GB_ASSERT(ce->args[0]->tav.type && ce->args[0]->tav.type->kind == Type_Pointer && ce->args[0]->tav.type->Pointer.elem->kind == Type_Named); + + return_type = ce->args[0]->tav.type; + } + } + + auto param_types = slice_make<Type *>(permanent_allocator(), proc.param_count + 2 - params_start); + param_types[0] = self_type; + param_types[1] = t_objc_SEL; + + for (isize i = params_start; i < params.count; i++) { + param_types[i+2-params_start] = params[i]->type; + } + + if (is_return_instancetype) { + operand->type = return_type; + } + + add_objc_proc_type(c, call, return_type, param_types); +} gb_internal ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *call, Ast *proc, Slice<Ast *> const &args, ProcInlining inlining, Type *type_hint) { if (proc != nullptr && @@ -8071,99 +8281,7 @@ gb_internal ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *c } if (operand->mode == Addressing_Type) { - Type *t = operand->type; - if (is_type_polymorphic_record(t)) { - CHECK_CALL_PARAMETER_MIXTURE_OR_RETURN("polymorphic type construction"); - - if (!is_type_named(t)) { - gbString s = expr_to_string(operand->expr); - error(call, "Illegal use of an unnamed polymorphic record, %s", s); - gb_string_free(s); - operand->mode = Addressing_Invalid; - operand->type = t_invalid;; - return Expr_Expr; - } - auto err = check_polymorphic_record_type(c, operand, call); - if (err == 0) { - Ast *ident = operand->expr; - while (ident->kind == Ast_SelectorExpr) { - Ast *s = ident->SelectorExpr.selector; - ident = s; - } - Type *ot = operand->type; - GB_ASSERT(ot->kind == Type_Named); - Entity *e = ot->Named.type_name; - add_entity_use(c, ident, e); - add_type_and_value(c, call, Addressing_Type, ot, empty_exact_value); - } else { - operand->mode = Addressing_Invalid; - operand->type = t_invalid; - } - } else { - CHECK_CALL_PARAMETER_MIXTURE_OR_RETURN("type conversion"); - - operand->mode = Addressing_Invalid; - isize arg_count = args.count; - switch (arg_count) { - case 0: - { - gbString str = type_to_string(t); - error(call, "Missing argument in conversion to '%s'", str); - gb_string_free(str); - } break; - default: - { - gbString str = type_to_string(t); - if (t->kind == Type_Basic) { - ERROR_BLOCK(); - switch (t->Basic.kind) { - case Basic_complex32: - case Basic_complex64: - case Basic_complex128: - error(call, "Too many arguments in conversion to '%s'", str); - error_line("\tSuggestion: %s(1+2i) or construct with 'complex'\n", str); - break; - case Basic_quaternion64: - case Basic_quaternion128: - case Basic_quaternion256: - error(call, "Too many arguments in conversion to '%s'", str); - error_line("\tSuggestion: %s(1+2i+3j+4k) or construct with 'quaternion'\n", str); - break; - default: - error(call, "Too many arguments in conversion to '%s'", str); - } - } else { - error(call, "Too many arguments in conversion to '%s'", str); - } - gb_string_free(str); - } break; - case 1: { - Ast *arg = args[0]; - if (arg->kind == Ast_FieldValue) { - error(call, "'field = value' cannot be used in a type conversion"); - arg = arg->FieldValue.value; - // NOTE(bill): Carry on the cast regardless - } - check_expr_with_type_hint(c, operand, arg, t); - if (operand->mode != Addressing_Invalid) { - if (is_type_polymorphic(t)) { - error(call, "A polymorphic type cannot be used in a type conversion"); - } else { - // NOTE(bill): Otherwise the compiler can override the polymorphic type - // as it assumes it is determining the type - check_cast(c, operand, t); - } - } - operand->type = t; - operand->expr = call; - if (operand->mode != Addressing_Invalid) { - update_untyped_expr_type(c, arg, t, false); - } - break; - } - } - } - return Expr_Expr; + return check_call_expr_as_type_cast(c, operand, call, args, type_hint); } if (operand->mode == Addressing_Builtin) { @@ -8335,9 +8453,10 @@ gb_internal ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *c if (c->curr_proc_decl == nullptr) { error(call, "Calling a '#force_inline' procedure that enables target features is not allowed at file scope"); } else { - GB_ASSERT(c->curr_proc_decl->entity); - GB_ASSERT(c->curr_proc_decl->entity->type->kind == Type_Proc); - String scope_features = c->curr_proc_decl->entity->type->Proc.enable_target_feature; + Entity *e = c->curr_proc_decl->entity.load(); + GB_ASSERT(e); + GB_ASSERT(e->type->kind == Type_Proc); + String scope_features = e->type->Proc.enable_target_feature; if (!check_target_feature_is_superset_of(scope_features, pt->Proc.enable_target_feature, &invalid)) { ERROR_BLOCK(); error(call, "Inlined procedure enables target feature '%.*s', this requires the calling procedure to at least enable the same feature", LIT(invalid)); @@ -8369,6 +8488,12 @@ gb_internal ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *c } } + Entity *proc_entity = entity_from_expr(call->CallExpr.proc); + bool is_objc_call = proc_entity && proc_entity->kind == Entity_Procedure && proc_entity->Procedure.is_objc_impl_or_import; + if (is_objc_call) { + check_objc_call_expr(c, operand, call, proc_entity, pt); + } + return Expr_Expr; } @@ -8630,7 +8755,7 @@ gb_internal bool check_range(CheckerContext *c, Ast *node, bool is_for_loop, Ope return true; } -gb_internal bool check_is_operand_compound_lit_constant(CheckerContext *c, Operand *o) { +gb_internal bool check_is_operand_compound_lit_constant(CheckerContext *c, Operand *o, Type *field_type) { if (is_operand_nil(*o)) { return true; } @@ -8645,6 +8770,13 @@ gb_internal bool check_is_operand_compound_lit_constant(CheckerContext *c, Opera return true; } } + if (field_type != nullptr && is_type_typeid(field_type) && o->mode == Addressing_Type) { + add_type_info_type(c, o->type); + return true; + } + if (is_type_any(field_type)) { + return false; + } return o->mode == Addressing_Constant; } @@ -8874,7 +9006,7 @@ gb_internal void add_constant_switch_case(CheckerContext *ctx, SeenMap *seen, Op isize count = multi_map_count(seen, key); if (count) { TEMPORARY_ALLOCATOR_GUARD(); - TypeAndToken *taps = gb_alloc_array(temporary_allocator(), TypeAndToken, count); + TypeAndToken *taps = temporary_alloc_array<TypeAndToken>(count); multi_map_get_all(seen, key, taps); for (isize i = 0; i < count; i++) { @@ -9069,6 +9201,52 @@ gb_internal ExprKind check_basic_directive_expr(CheckerContext *c, Operand *o, A return kind; } + +gb_internal void check_expr_as_value_for_ternary(CheckerContext *c, Operand *o, Ast *e, Type *type_hint) { + check_expr_base(c, o, e, type_hint); + check_not_tuple(c, o); + error_operand_no_value(o); + + switch (o->mode) { + case Addressing_Type: { + ERROR_BLOCK(); + gbString expr_str = expr_to_string(o->expr); + defer (gb_string_free(expr_str)); + + error(o->expr, "A type '%s' cannot be used as a runtime value", expr_str); + + error_line("\tSuggestion: If a runtime 'typeid' is wanted, use 'typeid_of' to convert a type\n"); + + o->mode = Addressing_Invalid; + + } break; + + case Addressing_Builtin: { + ERROR_BLOCK(); + gbString expr_str = expr_to_string(o->expr); + defer (gb_string_free(expr_str)); + + error(o->expr, "A built-in procedure '%s' cannot be used as a runtime value", expr_str); + + error_line("\tNote: Built-in procedures are implemented by the compiler and might not be actually instantiated procedures\n"); + + o->mode = Addressing_Invalid; + } break; + + case Addressing_ProcGroup: { + ERROR_BLOCK(); + gbString expr_str = expr_to_string(o->expr); + defer (gb_string_free(expr_str)); + + error(o->expr, "Cannot use overloaded procedure '%s' as a runtime value", expr_str); + + error_line("\tNote: Please specify which procedure in the procedure group to use, via cast or type inference\n"); + + o->mode = Addressing_Invalid; + } break; + } +} + gb_internal ExprKind check_ternary_if_expr(CheckerContext *c, Operand *o, Ast *node, Type *type_hint) { ExprKind kind = Expr_Expr; Operand cond = {Addressing_Invalid}; @@ -9082,7 +9260,7 @@ gb_internal ExprKind check_ternary_if_expr(CheckerContext *c, Operand *o, Ast *n Operand x = {Addressing_Invalid}; Operand y = {Addressing_Invalid}; - check_expr_or_type(c, &x, te->x, type_hint); + check_expr_as_value_for_ternary(c, &x, te->x, type_hint); node->viral_state_flags |= te->x->viral_state_flags; if (te->y != nullptr) { @@ -9090,7 +9268,7 @@ gb_internal ExprKind check_ternary_if_expr(CheckerContext *c, Operand *o, Ast *n if (type_hint == nullptr && is_type_typed(x.type)) { th = x.type; } - check_expr_or_type(c, &y, te->y, th); + check_expr_as_value_for_ternary(c, &y, te->y, th); node->viral_state_flags |= te->y->viral_state_flags; } else { error(node, "A ternary expression must have an else clause"); @@ -9117,6 +9295,20 @@ gb_internal ExprKind check_ternary_if_expr(CheckerContext *c, Operand *o, Ast *n return kind; } + if (x.mode == Addressing_Builtin && y.mode == Addressing_Builtin) { + if (type_hint == nullptr) { + error(node, "Built-in procedures cannot be used within a ternary expression since they have no well-defined signature"); + return kind; + } + } + + if (x.mode == Addressing_ProcGroup && y.mode == Addressing_ProcGroup) { + if (type_hint == nullptr) { + error(node, "Procedure groups cannot be used within a ternary expression since they have no well-defined signature that can be inferred without a context"); + return kind; + } + } + // NOTE(bill, 2023-01-30): Allow for expression like this: // x: union{f32} = f32(123) if cond else nil if (type_hint && !is_type_any(type_hint)) { @@ -9595,8 +9787,7 @@ gb_internal void check_compound_literal_field_values(CheckerContext *c, Slice<As break; } } - if (is_constant && - (is_type_any(ft) || is_type_union(ft) || is_type_raw_union(ft) || is_type_typeid(ft))) { + if (is_constant && elem_cannot_be_constant(ft)) { is_constant = false; } } @@ -9631,11 +9822,11 @@ gb_internal void check_compound_literal_field_values(CheckerContext *c, Slice<As Operand o = {}; check_expr_or_type(c, &o, fv->value, field->type); - if (is_type_any(field->type) || is_type_union(field->type) || is_type_raw_union(field->type) || is_type_typeid(field->type)) { + if (elem_cannot_be_constant(field->type)) { is_constant = false; } if (is_constant) { - is_constant = check_is_operand_compound_lit_constant(c, &o); + is_constant = check_is_operand_compound_lit_constant(c, &o, field->type); } u8 prev_bit_field_bit_size = c->bit_field_bit_size; @@ -9648,6 +9839,57 @@ gb_internal void check_compound_literal_field_values(CheckerContext *c, Slice<As c->bit_field_bit_size = prev_bit_field_bit_size; } + + if (bt->kind == Type_Struct && bt->Struct.is_all_or_none && elems.count > 0 && bt->Struct.fields.count > 0) { + PtrSet<Entity *> missing_fields = {}; + defer (ptr_set_destroy(&missing_fields)); + + for_array(i, bt->Struct.fields) { + Entity *field = bt->Struct.fields[i]; + String name = field->token.string; + if (is_blank_ident(name) || name == "") { + continue; + } + bool found = string_set_exists(&fields_visited, name); + String *raw_union = string_map_get(&fields_visited_through_raw_union, name); + if (!found && raw_union == nullptr) { + ptr_set_add(&missing_fields, field); + } + } + + if (missing_fields.count > 0) { + Ast *expr = o->expr; + if (expr == nullptr) { + GB_ASSERT(elems.count > 0); + expr = elems[elems.count-1]; + } + + ERROR_BLOCK(); + + if (build_context.terse_errors) { + gbString fields_string = gb_string_make(heap_allocator(), ""); + defer (gb_string_free(fields_string)); + isize i = 0; + FOR_PTR_SET(field, missing_fields) { + if (i > 0) { + fields_string = gb_string_appendc(fields_string, ", "); + } + String name = field->token.string; + fields_string = gb_string_append_length(fields_string, name.text, name.len); + i += 1; + } + + error(expr, "All or none of the fields must be assigned to a struct with '#all_or_none' applied, missing fields: %s", fields_string); + } else { + error(expr, "All or none of the fields must be assigned to a struct with '#all_or_none' applied, missing fields:"); + FOR_PTR_SET(field, missing_fields) { + gbString s = type_to_string(field->type); + error_line("\t%.*s: %s\n", LIT(field->token.string), s); + gb_string_free(s); + } + } + } + } } gb_internal bool is_expr_inferred_fixed_array(Ast *type_expr) { @@ -9668,7 +9910,10 @@ gb_internal bool is_expr_inferred_fixed_array(Ast *type_expr) { } gb_internal bool check_for_dynamic_literals(CheckerContext *c, Ast *node, AstCompoundLit *cl) { - if (cl->elems.count > 0 && (check_feature_flags(c, node) & OptInFeatureFlag_DynamicLiterals) == 0 && !build_context.dynamic_literals) { + if (cl->elems.count == 0) { + return false; + } + if ((check_feature_flags(c, node) & OptInFeatureFlag_DynamicLiterals) == 0 && !build_context.dynamic_literals) { ERROR_BLOCK(); error(node, "Compound literals of dynamic types are disabled by default"); error_line("\tSuggestion: If you want to enable them for this specific file, add '#+feature dynamic-literals' at the top of the file\n"); @@ -9679,9 +9924,13 @@ gb_internal bool check_for_dynamic_literals(CheckerContext *c, Ast *node, AstCom error_line("\tWarning: As '-default-to-panic-allocator' has been set, the dynamic compound literal may not be initialized as expected\n"); } return false; + } else if (c->curr_proc_decl != nullptr && c->curr_proc_calling_convention != ProcCC_Odin) { + if (c->scope != nullptr && (c->scope->flags & ScopeFlag_ContextDefined) == 0) { + error(node, "Compound literals of dynamic types require a 'context' to defined"); + } } - return cl->elems.count > 0; + return true; } gb_internal IntegerDivisionByZeroKind check_for_integer_division_by_zero(CheckerContext *c, Ast *node) { @@ -9801,7 +10050,7 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast * if (t->Struct.is_raw_union) { if (cl->elems.count > 0) { // NOTE: unions cannot be constant - is_constant = false; + is_constant = elem_type_can_be_constant(t); if (cl->elems[0]->kind != Ast_FieldValue) { gbString type_str = type_to_string(type); @@ -9861,11 +10110,11 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast * Operand o = {}; check_expr_or_type(c, &o, elem, field->type); - if (is_type_any(field->type) || is_type_union(field->type) || is_type_raw_union(field->type) || is_type_typeid(field->type)) { + if (elem_cannot_be_constant(field->type)) { is_constant = false; } if (is_constant) { - is_constant = check_is_operand_compound_lit_constant(c, &o); + is_constant = check_is_operand_compound_lit_constant(c, &o, field->type); } check_assignment(c, &o, field->type, str_lit("structure literal")); @@ -10010,7 +10259,9 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast * check_expr_with_type_hint(c, &operand, fv->value, elem_type); check_assignment(c, &operand, elem_type, context_name); - is_constant = is_constant && operand.mode == Addressing_Constant; + if (is_constant) { + is_constant = check_is_operand_compound_lit_constant(c, &operand, elem_type); + } } else { Operand op_index = {}; check_expr(c, &op_index, fv->field); @@ -10042,7 +10293,9 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast * check_expr_with_type_hint(c, &operand, fv->value, elem_type); check_assignment(c, &operand, elem_type, context_name); - is_constant = is_constant && operand.mode == Addressing_Constant; + if (is_constant) { + is_constant = check_is_operand_compound_lit_constant(c, &operand, elem_type); + } } } @@ -10069,7 +10322,9 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast * check_expr_with_type_hint(c, &operand, e, elem_type); check_assignment(c, &operand, elem_type, context_name); - is_constant = is_constant && operand.mode == Addressing_Constant; + if (is_constant) { + is_constant = check_is_operand_compound_lit_constant(c, &operand, elem_type); + } } if (max < index) { @@ -10243,7 +10498,9 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast * check_expr_with_type_hint(c, &operand, fv->value, elem_type); check_assignment(c, &operand, elem_type, context_name); - is_constant = is_constant && operand.mode == Addressing_Constant; + if (is_constant) { + is_constant = check_is_operand_compound_lit_constant(c, &operand, elem_type); + } TokenKind upper_op = Token_LtEq; if (op.kind == Token_RangeHalf) { @@ -10284,7 +10541,9 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast * check_expr_with_type_hint(c, &operand, fv->value, elem_type); check_assignment(c, &operand, elem_type, context_name); - is_constant = is_constant && operand.mode == Addressing_Constant; + if (is_constant) { + is_constant = check_is_operand_compound_lit_constant(c, &operand, elem_type); + } add_to_seen_map(c, &seen, op_index); } @@ -10314,7 +10573,9 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast * check_expr_with_type_hint(c, &operand, e, elem_type); check_assignment(c, &operand, elem_type, context_name); - is_constant = is_constant && operand.mode == Addressing_Constant; + if (is_constant) { + is_constant = check_is_operand_compound_lit_constant(c, &operand, elem_type); + } } if (max < index) { @@ -10920,7 +11181,7 @@ gb_internal ExprKind check_selector_call_expr(CheckerContext *c, Operand *o, Ast } } - auto modified_args = slice_make<Ast *>(heap_allocator(), ce->args.count+1); + auto modified_args = permanent_slice_make<Ast *>(ce->args.count+1); modified_args[0] = first_arg; slice_copy(&modified_args, ce->args, 1); ce->args = modified_args; @@ -11423,6 +11684,7 @@ gb_internal ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast o->mode = Addressing_Value; o->type = type; + o->value = exact_value_procedure(node); case_end; case_ast_node(te, TernaryIfExpr, node); @@ -11841,6 +12103,25 @@ gb_internal bool is_exact_value_zero(ExactValue const &v) { +gb_internal bool compare_exact_values_compound_lit(TokenKind op, ExactValue x, ExactValue y, bool *do_break_) { + ast_node(x_cl, CompoundLit, x.value_compound); + ast_node(y_cl, CompoundLit, y.value_compound); + + if (x_cl->elems.count != y_cl->elems.count) { + if (do_break_) *do_break_ = true; + } + + bool test = op == Token_CmpEq; + + for (isize i = 0; i < x_cl->elems.count; i++) { + Ast *lhs = x_cl->elems[i]; + Ast *rhs = y_cl->elems[i]; + if (compare_exact_values(op, lhs->tav.value, rhs->tav.value) != test) { + return !test; + } + } + return test; +} diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index ae88ff333..835f0162a 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -484,7 +484,7 @@ gb_internal Type *check_assignment_variable(CheckerContext *ctx, Operand *lhs, O } if (ident_node != nullptr) { ast_node(i, Ident, ident_node); - e = scope_lookup(ctx->scope, i->token.string); + e = scope_lookup(ctx->scope, i->token.string, i->hash); if (e != nullptr && e->kind == Entity_Variable) { used = (e->flags & EntityFlag_Used) != 0; // NOTE(bill): Make backup just in case } @@ -1812,8 +1812,9 @@ gb_internal void check_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) error(node, "Iteration over a bit_set of an enum is not allowed runtime type information (RTTI) has been disallowed"); } if (rs->vals.count == 1 && rs->vals[0] && rs->vals[0]->kind == Ast_Ident) { - String name = rs->vals[0]->Ident.token.string; - Entity *found = scope_lookup(ctx->scope, name); + AstIdent *ident = &rs->vals[0]->Ident; + String name = ident->token.string; + Entity *found = scope_lookup(ctx->scope, name, ident->hash); if (found && are_types_identical(found->type, t->BitSet.elem)) { ERROR_BLOCK(); gbString s = expr_to_string(expr); @@ -1857,8 +1858,9 @@ gb_internal void check_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) error(node, "#reverse for is not supported for map types, as maps are unordered"); } if (rs->vals.count == 1 && rs->vals[0] && rs->vals[0]->kind == Ast_Ident) { - String name = rs->vals[0]->Ident.token.string; - Entity *found = scope_lookup(ctx->scope, name); + AstIdent *ident = &rs->vals[0]->Ident; + String name = ident->token.string; + Entity *found = scope_lookup(ctx->scope, name, ident->hash); if (found && are_types_identical(found->type, t->Map.key)) { ERROR_BLOCK(); gbString s = expr_to_string(expr); @@ -1963,7 +1965,7 @@ gb_internal void check_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) } auto rhs = slice_from_array(vals); - auto lhs = slice_make<Ast *>(temporary_allocator(), rhs.count); + auto lhs = temporary_slice_make<Ast *>(rhs.count); slice_copy(&lhs, rs->vals); isize addressable_index = cast(isize)is_map; @@ -2539,6 +2541,82 @@ gb_internal void check_if_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) { check_close_scope(ctx); } +// NOTE(bill): This is very basic escape analysis +// This needs to be improved tremendously, and a lot of it done during the +// middle-end (or LLVM side) to improve checks and error messages +void check_unsafe_return(Operand const &o, Type *type, Ast *expr) { + auto const unsafe_return_error = [](Operand const &o, char const *msg, Type *extra_type=nullptr) { + gbString s = expr_to_string(o.expr); + if (extra_type) { + gbString t = type_to_string(extra_type); + error(o.expr, "It is unsafe to return %s ('%s') of type ('%s') from a procedure, as it uses the current stack frame's memory", msg, s, t); + gb_string_free(t); + } else { + error(o.expr, "It is unsafe to return %s ('%s') from a procedure, as it uses the current stack frame's memory", msg, s); + } + gb_string_free(s); + }; + + if (type == nullptr || expr == nullptr) { + return; + } + + if (expr->kind == Ast_CompoundLit && is_type_slice(type)) { + ast_node(cl, CompoundLit, expr); + if (cl->elems.count == 0) { + return; + } + unsafe_return_error(o, "a compound literal of a slice"); + } else if (expr->kind == Ast_UnaryExpr && expr->UnaryExpr.op.kind == Token_And) { + Ast *x = unparen_expr(expr->UnaryExpr.expr); + Entity *e = entity_of_node(x); + if (is_entity_local_variable(e)) { + unsafe_return_error(o, "the address of a local variable"); + } else if (x->kind == Ast_CompoundLit) { + unsafe_return_error(o, "the address of a compound literal"); + } else if (x->kind == Ast_IndexExpr) { + Entity *f = entity_of_node(x->IndexExpr.expr); + if (f && (is_type_array_like(f->type) || is_type_matrix(f->type))) { + if (is_entity_local_variable(f)) { + unsafe_return_error(o, "the address of an indexed variable", f->type); + } + } + } else if (x->kind == Ast_MatrixIndexExpr) { + Entity *f = entity_of_node(x->MatrixIndexExpr.expr); + if (f && (is_type_matrix(f->type) && is_entity_local_variable(f))) { + unsafe_return_error(o, "the address of an indexed variable", f->type); + } + } + } else if (expr->kind == Ast_SliceExpr) { + Ast *x = unparen_expr(expr->SliceExpr.expr); + Entity *e = entity_of_node(x); + if (is_entity_local_variable(e) && is_type_array(e->type)) { + unsafe_return_error(o, "a slice of a local variable"); + } else if (x->kind == Ast_CompoundLit) { + unsafe_return_error(o, "a slice of a compound literal"); + } + } else if (o.mode == Addressing_Constant && is_type_slice(type)) { + if (is_load_directive_call(o.expr)) { + return; + } + + ERROR_BLOCK(); + unsafe_return_error(o, "a compound literal of a slice"); + error_line("\tNote: A constant slice value will use the memory of the current stack frame\n"); + } else if (expr->kind == Ast_CompoundLit) { + ast_node(cl, CompoundLit, expr); + for (Ast *elem : cl->elems) { + if (elem->kind == Ast_FieldValue) { + ast_node(fv, FieldValue, elem); + Entity *e = entity_of_node(fv->field); + if (e != nullptr) { + check_unsafe_return(o, e->type, fv->value); + } + } + } + } +} + gb_internal void check_return_stmt(CheckerContext *ctx, Ast *node) { ast_node(rs, ReturnStmt, node); @@ -2567,8 +2645,9 @@ gb_internal void check_return_stmt(CheckerContext *ctx, Ast *node) { result_count = proc_type->Proc.results->Tuple.variables.count; } - auto operands = array_make<Operand>(heap_allocator(), 0, 2*rs->results.count); - defer (array_free(&operands)); + TEMPORARY_ALLOCATOR_GUARD(); + + auto operands = array_make<Operand>(temporary_allocator(), 0, 2*rs->results.count); check_unpack_arguments(ctx, result_entities, result_count, &operands, rs->results, UnpackFlag_AllowOk); @@ -2614,61 +2693,7 @@ gb_internal void check_return_stmt(CheckerContext *ctx, Ast *node) { expr = unparen_expr(arg); } - auto unsafe_return_error = [](Operand const &o, char const *msg, Type *extra_type=nullptr) { - gbString s = expr_to_string(o.expr); - if (extra_type) { - gbString t = type_to_string(extra_type); - error(o.expr, "It is unsafe to return %s ('%s') of type ('%s') from a procedure, as it uses the current stack frame's memory", msg, s, t); - gb_string_free(t); - } else { - error(o.expr, "It is unsafe to return %s ('%s') from a procedure, as it uses the current stack frame's memory", msg, s); - } - gb_string_free(s); - }; - - - // NOTE(bill): This is very basic escape analysis - // This needs to be improved tremendously, and a lot of it done during the - // middle-end (or LLVM side) to improve checks and error messages - if (expr->kind == Ast_CompoundLit && is_type_slice(o.type)) { - ast_node(cl, CompoundLit, expr); - if (cl->elems.count == 0) { - continue; - } - unsafe_return_error(o, "a compound literal of a slice"); - } else if (expr->kind == Ast_UnaryExpr && expr->UnaryExpr.op.kind == Token_And) { - Ast *x = unparen_expr(expr->UnaryExpr.expr); - Entity *e = entity_of_node(x); - if (is_entity_local_variable(e)) { - unsafe_return_error(o, "the address of a local variable"); - } else if (x->kind == Ast_CompoundLit) { - unsafe_return_error(o, "the address of a compound literal"); - } else if (x->kind == Ast_IndexExpr) { - Entity *f = entity_of_node(x->IndexExpr.expr); - if (f && (is_type_array_like(f->type) || is_type_matrix(f->type))) { - if (is_entity_local_variable(f)) { - unsafe_return_error(o, "the address of an indexed variable", f->type); - } - } - } else if (x->kind == Ast_MatrixIndexExpr) { - Entity *f = entity_of_node(x->MatrixIndexExpr.expr); - if (f && (is_type_matrix(f->type) && is_entity_local_variable(f))) { - unsafe_return_error(o, "the address of an indexed variable", f->type); - } - } - } else if (expr->kind == Ast_SliceExpr) { - Ast *x = unparen_expr(expr->SliceExpr.expr); - Entity *e = entity_of_node(x); - if (is_entity_local_variable(e) && is_type_array(e->type)) { - unsafe_return_error(o, "a slice of a local variable"); - } else if (x->kind == Ast_CompoundLit) { - unsafe_return_error(o, "a slice of a compound literal"); - } - } else if (o.mode == Addressing_Constant && is_type_slice(o.type)) { - ERROR_BLOCK(); - unsafe_return_error(o, "a compound literal of a slice"); - error_line("\tNote: A constant slice value will use the memory of the current stack frame\n"); - } + check_unsafe_return(o, o.type, expr); } } diff --git a/src/check_type.cpp b/src/check_type.cpp index a104d6fc0..af07efd8f 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -267,19 +267,19 @@ gb_internal bool check_custom_align(CheckerContext *ctx, Ast *node, i64 *align_, gb_internal GenTypesData *ensure_polymorphic_record_entity_has_gen_types(CheckerContext *ctx, Type *original_type) { - mutex_lock(&ctx->info->gen_types_mutex); // @@global - GenTypesData *found_gen_types = nullptr; - auto *found_gen_types_ptr = map_get(&ctx->info->gen_types, original_type); - if (found_gen_types_ptr == nullptr) { + + GB_ASSERT(original_type->kind == Type_Named); + mutex_lock(&original_type->Named.gen_types_data_mutex); + if (original_type->Named.gen_types_data == nullptr) { GenTypesData *gen_types = gb_alloc_item(permanent_allocator(), GenTypesData); gen_types->types = array_make<Entity *>(heap_allocator()); - map_set(&ctx->info->gen_types, original_type, gen_types); - found_gen_types_ptr = map_get(&ctx->info->gen_types, original_type); + original_type->Named.gen_types_data = gen_types; } - found_gen_types = *found_gen_types_ptr; - GB_ASSERT(found_gen_types != nullptr); - mutex_unlock(&ctx->info->gen_types_mutex); // @@global + found_gen_types = original_type->Named.gen_types_data; + + mutex_unlock(&original_type->Named.gen_types_data_mutex); + return found_gen_types; } @@ -312,6 +312,7 @@ gb_internal void add_polymorphic_record_entity(CheckerContext *ctx, Ast *node, T e->state = EntityState_Resolved; e->file = ctx->file; e->pkg = pkg; + e->TypeName.original_type_for_parapoly = original_type; add_entity_use(ctx, node, e); } @@ -653,9 +654,10 @@ gb_internal void check_struct_type(CheckerContext *ctx, Type *struct_type, Ast * context = str_lit("struct #raw_union"); } - struct_type->Struct.node = node; - struct_type->Struct.scope = ctx->scope; - struct_type->Struct.is_packed = st->is_packed; + struct_type->Struct.node = node; + struct_type->Struct.scope = ctx->scope; + struct_type->Struct.is_packed = st->is_packed; + struct_type->Struct.is_all_or_none = st->is_all_or_none; struct_type->Struct.polymorphic_params = check_record_polymorphic_params( ctx, st->polymorphic_params, &struct_type->Struct.is_polymorphic, @@ -1106,7 +1108,7 @@ gb_internal void check_bit_field_type(CheckerContext *ctx, Type *bit_field_type, GB_ASSERT(fields.count <= bf->fields.count); - auto bit_offsets = slice_make<i64>(permanent_allocator(), fields.count); + auto bit_offsets = permanent_slice_make<i64>(fields.count); i64 curr_offset = 0; for_array(i, bit_sizes) { bit_offsets[i] = curr_offset; @@ -1610,6 +1612,12 @@ gb_internal Type *determine_type_from_polymorphic(CheckerContext *ctx, Type *pol error_line("\tSuggestion: Try slicing the value with '%s[:]'\n", os); gb_string_free(os); } + } else if (is_type_pointer(poly_type)) { + if (is_polymorphic_type_assignable(ctx, type_deref(poly_type), operand.type, /*compound*/false, /*modify_type*/false)) { + gbString os = expr_to_string(operand.expr); + error_line("\tSuggestion: Did you mean '&%s'?\n", os); + gb_string_free(os); + } } } return t_invalid; @@ -1626,6 +1634,8 @@ gb_internal bool is_expr_from_a_parameter(CheckerContext *ctx, Ast *expr) { } else if (expr->kind == Ast_Ident) { Operand x= {}; Entity *e = check_ident(ctx, &x, expr, nullptr, nullptr, true); + GB_ASSERT(e != nullptr); + if (e->flags & EntityFlag_Param) { return true; } @@ -2707,7 +2717,7 @@ gb_internal Type *get_map_cell_type(Type *type) { // Padding exists Type *s = alloc_type_struct(); Scope *scope = create_scope(nullptr, nullptr); - s->Struct.fields = slice_make<Entity *>(permanent_allocator(), 2); + s->Struct.fields = permanent_slice_make<Entity *>(2); s->Struct.fields[0] = alloc_entity_field(scope, make_token_ident("v"), alloc_type_array(type, len), false, 0, EntityState_Resolved); s->Struct.fields[1] = alloc_entity_field(scope, make_token_ident("_"), alloc_type_array(t_u8, padding), false, 1, EntityState_Resolved); s->Struct.scope = scope; @@ -2732,7 +2742,7 @@ gb_internal void init_map_internal_debug_types(Type *type) { Type *metadata_type = alloc_type_struct(); Scope *metadata_scope = create_scope(nullptr, nullptr); - metadata_type->Struct.fields = slice_make<Entity *>(permanent_allocator(), 5); + metadata_type->Struct.fields = permanent_slice_make<Entity *>(5); metadata_type->Struct.fields[0] = alloc_entity_field(metadata_scope, make_token_ident("key"), key, false, 0, EntityState_Resolved); metadata_type->Struct.fields[1] = alloc_entity_field(metadata_scope, make_token_ident("value"), value, false, 1, EntityState_Resolved); metadata_type->Struct.fields[2] = alloc_entity_field(metadata_scope, make_token_ident("hash"), t_uintptr, false, 2, EntityState_Resolved); @@ -2750,7 +2760,7 @@ gb_internal void init_map_internal_debug_types(Type *type) { Scope *scope = create_scope(nullptr, nullptr); Type *debug_type = alloc_type_struct(); - debug_type->Struct.fields = slice_make<Entity *>(permanent_allocator(), 3); + debug_type->Struct.fields = permanent_slice_make<Entity *>(3); debug_type->Struct.fields[0] = alloc_entity_field(scope, make_token_ident("data"), metadata_type, false, 0, EntityState_Resolved); debug_type->Struct.fields[1] = alloc_entity_field(scope, make_token_ident("len"), t_int, false, 1, EntityState_Resolved); debug_type->Struct.fields[2] = alloc_entity_field(scope, make_token_ident("allocator"), t_allocator, false, 2, EntityState_Resolved); @@ -2983,13 +2993,13 @@ gb_internal bool complete_soa_type(Checker *checker, Type *t, bool wait_to_finis if (wait_to_finish) { wait_signal_until_available(&old_struct->Struct.fields_wait_signal); } else { - GB_ASSERT(old_struct->Struct.fields_wait_signal.futex.load()); + GB_ASSERT(old_struct->Struct.fields_wait_signal.futex.load() != 0); } field_count = old_struct->Struct.fields.count; - t->Struct.fields = slice_make<Entity *>(permanent_allocator(), field_count+extra_field_count); - t->Struct.tags = gb_alloc_array(permanent_allocator(), String, field_count+extra_field_count); + t->Struct.fields = permanent_slice_make<Entity *>(field_count+extra_field_count); + t->Struct.tags = permanent_alloc_array<String>(field_count+extra_field_count); auto const &add_entity = [](Scope *scope, Entity *entity) { @@ -3107,7 +3117,7 @@ gb_internal Type *make_soa_struct_internal(CheckerContext *ctx, Ast *array_typ_e if (is_polymorphic) { field_count = 0; - soa_struct->Struct.fields = slice_make<Entity *>(permanent_allocator(), field_count+extra_field_count); + soa_struct->Struct.fields = permanent_slice_make<Entity *>(field_count+extra_field_count); soa_struct->Struct.tags = gb_alloc_array(permanent_allocator(), String, field_count+extra_field_count); soa_struct->Struct.soa_count = 0; @@ -3117,7 +3127,7 @@ gb_internal Type *make_soa_struct_internal(CheckerContext *ctx, Ast *array_typ_e Type *old_array = base_type(elem); field_count = cast(isize)old_array->Array.count; - soa_struct->Struct.fields = slice_make<Entity *>(permanent_allocator(), field_count+extra_field_count); + soa_struct->Struct.fields = permanent_slice_make<Entity *>(field_count+extra_field_count); soa_struct->Struct.tags = gb_alloc_array(permanent_allocator(), String, field_count+extra_field_count); string_map_init(&scope->elements, 8); @@ -3159,8 +3169,8 @@ gb_internal Type *make_soa_struct_internal(CheckerContext *ctx, Ast *array_typ_e if (old_struct->Struct.fields_wait_signal.futex.load()) { field_count = old_struct->Struct.fields.count; - soa_struct->Struct.fields = slice_make<Entity *>(permanent_allocator(), field_count+extra_field_count); - soa_struct->Struct.tags = gb_alloc_array(permanent_allocator(), String, field_count+extra_field_count); + soa_struct->Struct.fields = permanent_slice_make<Entity *>(field_count+extra_field_count); + soa_struct->Struct.tags = permanent_alloc_array<String>(field_count+extra_field_count); for_array(i, old_struct->Struct.fields) { Entity *old_field = old_struct->Struct.fields[i]; @@ -3355,7 +3365,7 @@ gb_internal void check_array_type_internal(CheckerContext *ctx, Ast *e, Type **t } } gb_internal bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, Type *named_type) { - GB_ASSERT_NOT_NULL(type); + GB_ASSERT(type != nullptr); if (e == nullptr) { *type = t_invalid; return true; @@ -3512,8 +3522,9 @@ gb_internal bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, T case_ast_node(pt, PointerType, e); CheckerContext c = *ctx; - c.type_path = new_checker_type_path(); - defer (destroy_checker_type_path(c.type_path)); + + TEMPORARY_ALLOCATOR_GUARD(); + c.type_path = new_checker_type_path(temporary_allocator()); Type *elem = t_invalid; Operand o = {}; @@ -3747,8 +3758,8 @@ gb_internal bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, T gb_internal Type *check_type(CheckerContext *ctx, Ast *e) { CheckerContext c = *ctx; - c.type_path = new_checker_type_path(); - defer (destroy_checker_type_path(c.type_path)); + TEMPORARY_ALLOCATOR_GUARD(); + c.type_path = new_checker_type_path(temporary_allocator()); return check_type_expr(&c, e, nullptr); } diff --git a/src/checker.cpp b/src/checker.cpp index e5dda2aa7..33121b453 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -380,16 +380,25 @@ gb_internal Entity *scope_lookup_current(Scope *s, String const &name) { } -gb_internal void scope_lookup_parent(Scope *scope, String const &name, Scope **scope_, Entity **entity_) { +gb_global std::atomic<bool> in_single_threaded_checker_stage; + +gb_internal void scope_lookup_parent(Scope *scope, String const &name, Scope **scope_, Entity **entity_, u32 hash) { + bool is_single_threaded = in_single_threaded_checker_stage.load(std::memory_order_relaxed); if (scope != nullptr) { bool gone_thru_proc = false; bool gone_thru_package = false; - StringHashKey key = string_hash_string(name); + StringHashKey key = {}; + if (hash) { + key.hash = hash; + key.string = name; + } else { + key = string_hash_string(name); + } for (Scope *s = scope; s != nullptr; s = s->parent) { Entity **found = nullptr; - rw_mutex_shared_lock(&s->mutex); + if (!is_single_threaded) rw_mutex_shared_lock(&s->mutex); found = string_map_get(&s->elements, key); - rw_mutex_shared_unlock(&s->mutex); + if (!is_single_threaded) rw_mutex_shared_unlock(&s->mutex); if (found) { Entity *e = *found; if (gone_thru_proc) { @@ -424,9 +433,9 @@ gb_internal void scope_lookup_parent(Scope *scope, String const &name, Scope **s if (scope_) *scope_ = nullptr; } -gb_internal Entity *scope_lookup(Scope *s, String const &name) { +gb_internal Entity *scope_lookup(Scope *s, String const &name, u32 hash) { Entity *entity = nullptr; - scope_lookup_parent(s, name, nullptr, &entity); + scope_lookup_parent(s, name, nullptr, &entity, hash); return entity; } @@ -507,11 +516,9 @@ end:; return result; } -gb_global bool in_single_threaded_checker_stage = false; - gb_internal Entity *scope_insert(Scope *s, Entity *entity) { String name = entity->token.string; - if (in_single_threaded_checker_stage) { + if (in_single_threaded_checker_stage.load(std::memory_order_relaxed)) { return scope_insert_with_name_no_mutex(s, name, entity); } else { return scope_insert_with_name(s, name, entity); @@ -722,9 +729,10 @@ gb_internal bool check_vet_unused(Checker *c, Entity *e, VettedEntity *ve) { gb_internal void check_scope_usage_internal(Checker *c, Scope *scope, u64 vet_flags, bool per_entity) { u64 original_vet_flags = vet_flags; + + TEMPORARY_ALLOCATOR_GUARD(); Array<VettedEntity> vetted_entities = {}; - array_init(&vetted_entities, heap_allocator()); - defer (array_free(&vetted_entities)); + array_init(&vetted_entities, temporary_allocator()); rw_mutex_shared_lock(&scope->mutex); for (auto const &entry : scope->elements) { @@ -782,8 +790,10 @@ gb_internal void check_scope_usage_internal(Checker *c, Scope *scope, u64 vet_fl // Is >256 KiB good enough? if (sz > 1ll<<18) { bool is_ref = false; - if((e->flags & EntityFlag_ForValue) != 0) { + if ((e->flags & EntityFlag_ForValue) != 0) { is_ref = type_deref(e->Variable.for_loop_parent_type) != NULL; + } else if ((e->flags & EntityFlag_SwitchValue) != 0) { + is_ref = !(e->flags & EntityFlag_Value); } if(!is_ref) { gbString type_str = type_to_string(e->type); @@ -852,9 +862,13 @@ gb_internal void check_scope_usage(Checker *c, Scope *scope, u64 vet_flags) { gb_internal void add_dependency(CheckerInfo *info, DeclInfo *d, Entity *e) { - rw_mutex_lock(&d->deps_mutex); - ptr_set_add(&d->deps, e); - rw_mutex_unlock(&d->deps_mutex); + if (in_single_threaded_checker_stage.load(std::memory_order_relaxed)) { + ptr_set_add(&d->deps, e); + } else { + rw_mutex_lock(&d->deps_mutex); + ptr_set_add(&d->deps, e); + rw_mutex_unlock(&d->deps_mutex); + } } gb_internal void add_type_info_dependency(CheckerInfo *info, DeclInfo *d, Type *type) { if (d == nullptr || type == nullptr) { @@ -911,6 +925,22 @@ gb_internal AstPackage *get_core_package(CheckerInfo *info, String name) { return *found; } + +gb_internal AstPackage *try_get_core_package(CheckerInfo *info, String name) { + if (name == "runtime") { + return get_runtime_package(info); + } + + gbAllocator a = heap_allocator(); + String path = get_fullpath_core_collection(a, name, nullptr); + defer (gb_free(a, path.text)); + auto found = string_map_get(&info->packages, path); + if (found == nullptr) { + return nullptr; + } + return *found; +} + gb_internal void add_package_dependency(CheckerContext *c, char const *package_name, char const *name, bool required=false) { String n = make_string_c(name); AstPackage *p = get_core_package(&c->checker->info, make_string_c(package_name)); @@ -1404,6 +1434,8 @@ gb_internal void init_universal(void) { t_objc_SEL = alloc_type_pointer(t_objc_selector); t_objc_Class = alloc_type_pointer(t_objc_class); t_objc_Ivar = alloc_type_pointer(t_objc_ivar); + + t_objc_instancetype = add_global_type_name(intrinsics_pkg->scope, str_lit("objc_instancetype"), t_objc_id); } } @@ -1419,13 +1451,10 @@ gb_internal void init_checker_info(CheckerInfo *i) { array_init(&i->entities, a); map_init(&i->global_untyped); string_map_init(&i->foreigns); - // map_init(&i->gen_procs); - map_init(&i->gen_types); type_set_init(&i->min_dep_type_info_set); map_init(&i->min_dep_type_info_index_map); - // map_init(&i->type_info_map); string_map_init(&i->files); string_map_init(&i->packages); array_init(&i->variable_init_order, a); @@ -1441,7 +1470,8 @@ gb_internal void init_checker_info(CheckerInfo *i) { map_init(&i->objc_method_implementations); string_map_init(&i->load_file_cache); - array_init(&i->all_procedures, heap_allocator()); + array_init(&i->all_procedures, a); + mpsc_init(&i->all_procedures_queue, a); mpsc_init(&i->entity_queue, a); // 1<<20); mpsc_init(&i->definition_queue, a); //); // 1<<20); @@ -1463,8 +1493,6 @@ gb_internal void destroy_checker_info(CheckerInfo *i) { array_free(&i->entities); map_destroy(&i->global_untyped); string_map_destroy(&i->foreigns); - // map_destroy(&i->gen_procs); - map_destroy(&i->gen_types); type_set_destroy(&i->min_dep_type_info_set); map_destroy(&i->min_dep_type_info_index_map); @@ -1475,6 +1503,10 @@ gb_internal void destroy_checker_info(CheckerInfo *i) { array_free(&i->required_foreign_imports_through_force); array_free(&i->defineables); + array_free(&i->all_procedures); + + mpsc_destroy(&i->all_procedures_queue); + mpsc_destroy(&i->entity_queue); mpsc_destroy(&i->definition_queue); mpsc_destroy(&i->required_global_variable_queue); @@ -1487,9 +1519,12 @@ gb_internal void destroy_checker_info(CheckerInfo *i) { map_destroy(&i->objc_msgSend_types); string_set_destroy(&i->obcj_class_name_set); - mpsc_destroy(&i->objc_class_implementations); map_destroy(&i->objc_method_implementations); + // NOTE(harold): Disabling this: It can cause the 'count == 0' assert to trigger + // when there's checker errors and the queue is still full as it did not reach the generation stage. + // mpsc_destroy(&i->objc_class_implementations); + string_map_destroy(&i->load_file_cache); string_map_destroy(&i->load_directory_cache); map_destroy(&i->load_directory_map); @@ -1502,12 +1537,12 @@ gb_internal CheckerContext make_checker_context(Checker *c) { ctx.scope = builtin_pkg->scope; ctx.pkg = builtin_pkg; - ctx.type_path = new_checker_type_path(); + ctx.type_path = new_checker_type_path(heap_allocator()); ctx.type_level = 0; return ctx; } gb_internal void destroy_checker_context(CheckerContext *ctx) { - destroy_checker_type_path(ctx->type_path); + destroy_checker_type_path(ctx->type_path, heap_allocator()); } gb_internal bool add_curr_ast_file(CheckerContext *ctx, AstFile *file) { @@ -1712,7 +1747,7 @@ gb_internal void check_remove_expr_info(CheckerContext *c, Ast *e) { } gb_internal isize type_info_index(CheckerInfo *info, TypeInfoPair pair, bool error_on_failure) { - mutex_lock(&info->minimum_dependency_type_info_mutex); + rw_mutex_shared_lock(&info->minimum_dependency_type_info_mutex); isize entry_index = -1; u64 hash = pair.hash; @@ -1720,7 +1755,7 @@ gb_internal isize type_info_index(CheckerInfo *info, TypeInfoPair pair, bool err if (found_entry_index) { entry_index = *found_entry_index; } - mutex_unlock(&info->minimum_dependency_type_info_mutex); + rw_mutex_shared_unlock(&info->minimum_dependency_type_info_mutex); if (error_on_failure && entry_index < 0) { compiler_error("Type_Info for '%s' could not be found", type_to_string(pair.type)); @@ -1758,7 +1793,7 @@ gb_internal void add_untyped(CheckerContext *c, Ast *expr, AddressingMode mode, check_set_expr_info(c, expr, mode, type, value); } -gb_internal void add_type_and_value(CheckerContext *ctx, Ast *expr, AddressingMode mode, Type *type, ExactValue const &value) { +gb_internal void add_type_and_value(CheckerContext *ctx, Ast *expr, AddressingMode mode, Type *type, ExactValue const &value, bool use_mutex) { if (expr == nullptr) { return; } @@ -1776,7 +1811,7 @@ gb_internal void add_type_and_value(CheckerContext *ctx, Ast *expr, AddressingMo mutex = &ctx->pkg->type_and_value_mutex; } - mutex_lock(mutex); + if (use_mutex) mutex_lock(mutex); Ast *prev_expr = nullptr; while (prev_expr != expr) { prev_expr = expr; @@ -1801,7 +1836,7 @@ gb_internal void add_type_and_value(CheckerContext *ctx, Ast *expr, AddressingMo break; }; } - mutex_unlock(mutex); + if (use_mutex) mutex_unlock(mutex); } gb_internal void add_entity_definition(CheckerInfo *i, Ast *identifier, Entity *entity) { @@ -2043,8 +2078,8 @@ gb_internal void add_entity_and_decl_info(CheckerContext *c, Ast *identifier, En add_entity_definition(info, identifier, e); GB_ASSERT(e->decl_info == nullptr); e->decl_info = d; - d->entity = e; e->pkg = c->pkg; + d->entity.store(e); isize queue_count = -1; bool is_lazy = false; @@ -2345,11 +2380,9 @@ gb_internal void check_procedure_later(Checker *c, ProcInfo *info) { } if (DEBUG_CHECK_ALL_PROCEDURES) { - MUTEX_GUARD_BLOCK(&c->info.all_procedures_mutex) { - GB_ASSERT(info != nullptr); - GB_ASSERT(info->decl != nullptr); - array_add(&c->info.all_procedures, info); - } + GB_ASSERT(info != nullptr); + GB_ASSERT(info->decl != nullptr); + mpsc_enqueue(&c->info.all_procedures_queue, info); } } @@ -2377,7 +2410,7 @@ gb_internal void add_min_dep_type_info(Checker *c, Type *t) { return; } - if (type_set_update(&c->info.min_dep_type_info_set, t)) { + if (type_set_update_with_mutex(&c->info.min_dep_type_info_set, t, &c->info.min_dep_type_info_set_mutex)) { return; } @@ -2552,15 +2585,15 @@ gb_internal void add_min_dep_type_info(Checker *c, Type *t) { } } +gb_internal void add_dependency_to_set_threaded(Checker *c, Entity *entity); + +gb_global std::atomic<Checker *> global_checker_ptr; gb_internal void add_dependency_to_set(Checker *c, Entity *entity) { if (entity == nullptr) { return; } - CheckerInfo *info = &c->info; - auto *set = &info->minimum_dependency_set; - if (entity->type != nullptr && is_type_polymorphic(entity->type)) { DeclInfo *decl = decl_info_of_entity(entity); @@ -2569,7 +2602,7 @@ gb_internal void add_dependency_to_set(Checker *c, Entity *entity) { } } - if (ptr_set_update(set, entity)) { + if (entity->min_dep_count.fetch_add(1, std::memory_order_relaxed) > 0) { return; } @@ -2580,29 +2613,108 @@ gb_internal void add_dependency_to_set(Checker *c, Entity *entity) { for (TypeInfoPair const tt : decl->type_info_deps) { add_min_dep_type_info(c, tt.type); } + FOR_PTR_SET(e, decl->deps) { + switch (e->kind) { + case Entity_Procedure: + if (e->Procedure.is_foreign) { + Entity *fl = e->Procedure.foreign_library; + if (fl != nullptr) { + GB_ASSERT_MSG(fl->kind == Entity_LibraryName && + (fl->flags&EntityFlag_Used), + "%.*s", LIT(entity->token.string)); + add_dependency_to_set(c, fl); + } + } + break; + case Entity_Variable: + if (e->Variable.is_foreign) { + Entity *fl = e->Variable.foreign_library; + if (fl != nullptr) { + GB_ASSERT_MSG(fl->kind == Entity_LibraryName && + (fl->flags&EntityFlag_Used), + "%.*s", LIT(entity->token.string)); + add_dependency_to_set(c, fl); + } + } + break; + } + } - for (Entity *e : decl->deps) { + FOR_PTR_SET(e, decl->deps) { add_dependency_to_set(c, e); - if (e->kind == Entity_Procedure && e->Procedure.is_foreign) { - Entity *fl = e->Procedure.foreign_library; - if (fl != nullptr) { - GB_ASSERT_MSG(fl->kind == Entity_LibraryName && - (fl->flags&EntityFlag_Used), - "%.*s", LIT(entity->token.string)); - add_dependency_to_set(c, fl); + } + +} +gb_internal WORKER_TASK_PROC(add_dependency_to_set_worker) { + Checker *c = global_checker_ptr.load(std::memory_order_relaxed); + Entity *entity = cast(Entity *)data; + if (entity == nullptr) { + return 0; + } + + if (entity->type != nullptr && + is_type_polymorphic(entity->type)) { + DeclInfo *decl = decl_info_of_entity(entity); + if (decl != nullptr && decl->gen_proc_type == nullptr) { + return 0; + } + } + + if (entity->min_dep_count.fetch_add(1, std::memory_order_relaxed) > 0) { + return 0; + } + + DeclInfo *decl = decl_info_of_entity(entity); + if (decl == nullptr) { + return 0; + } + for (TypeInfoPair const tt : decl->type_info_deps) { + add_min_dep_type_info(c, tt.type); + } + + FOR_PTR_SET(e, decl->deps) { + switch (e->kind) { + case Entity_Procedure: + if (e->Procedure.is_foreign) { + Entity *fl = e->Procedure.foreign_library; + if (fl != nullptr) { + GB_ASSERT_MSG(fl->kind == Entity_LibraryName && + (fl->flags&EntityFlag_Used), + "%.*s", LIT(entity->token.string)); + add_dependency_to_set_threaded(c, fl); + } } - } else if (e->kind == Entity_Variable && e->Variable.is_foreign) { - Entity *fl = e->Variable.foreign_library; - if (fl != nullptr) { - GB_ASSERT_MSG(fl->kind == Entity_LibraryName && - (fl->flags&EntityFlag_Used), - "%.*s", LIT(entity->token.string)); - add_dependency_to_set(c, fl); + break; + case Entity_Variable: + if (e->Variable.is_foreign) { + Entity *fl = e->Variable.foreign_library; + if (fl != nullptr) { + GB_ASSERT_MSG(fl->kind == Entity_LibraryName && + (fl->flags&EntityFlag_Used), + "%.*s", LIT(entity->token.string)); + add_dependency_to_set_threaded(c, fl); + } } + break; } } + + FOR_PTR_SET(e, decl->deps) { + add_dependency_to_set_threaded(c, e); + } + + return 0; +} + + +gb_internal void add_dependency_to_set_threaded(Checker *c, Entity *entity) { + if (entity == nullptr) { + return; + } + thread_pool_add_task(add_dependency_to_set_worker, entity); } + gb_internal void force_add_dependency_entity(Checker *c, Scope *scope, String const &name) { Entity *e = scope_lookup(scope, name); if (e == nullptr) { @@ -2652,27 +2764,35 @@ gb_internal void collect_testing_procedures_of_package(Checker *c, AstPackage *p } gb_internal void generate_minimum_dependency_set_internal(Checker *c, Entity *start) { + // auto const &add_to_set = add_dependency_to_set; + auto const &add_to_set = add_dependency_to_set_threaded; + + Scope *builtin_scope = builtin_pkg->scope; for_array(i, c->info.definitions) { Entity *e = c->info.definitions[i]; - if (e->scope == builtin_pkg->scope) { + if (e->scope == builtin_scope) { if (e->type == nullptr) { - add_dependency_to_set(c, e); + add_to_set(c, e); + } + } else if (e->kind == Entity_Procedure) { + if (e->Procedure.is_export) { + add_to_set(c, e); + } + } else if (e->kind == Entity_Variable) { + if (e->Variable.is_export) { + add_to_set(c, e); } - } else if (e->kind == Entity_Procedure && e->Procedure.is_export) { - add_dependency_to_set(c, e); - } else if (e->kind == Entity_Variable && e->Variable.is_export) { - add_dependency_to_set(c, e); } } for (Entity *e; mpsc_dequeue(&c->info.required_foreign_imports_through_force_queue, &e); /**/) { array_add(&c->info.required_foreign_imports_through_force, e); - add_dependency_to_set(c, e); + add_to_set(c, e); } for (Entity *e; mpsc_dequeue(&c->info.required_global_variable_queue, &e); /**/) { e->flags |= EntityFlag_Used; - add_dependency_to_set(c, e); + add_to_set(c, e); } for_array(i, c->info.entities) { @@ -2680,16 +2800,16 @@ gb_internal void generate_minimum_dependency_set_internal(Checker *c, Entity *st switch (e->kind) { case Entity_Variable: if (e->Variable.is_export) { - add_dependency_to_set(c, e); + add_to_set(c, e); } else if (e->flags & EntityFlag_Require) { - add_dependency_to_set(c, e); + add_to_set(c, e); } break; case Entity_Procedure: if (e->Procedure.is_export) { - add_dependency_to_set(c, e); + add_to_set(c, e); } else if (e->flags & EntityFlag_Require) { - add_dependency_to_set(c, e); + add_to_set(c, e); } if (e->flags & EntityFlag_Init) { Type *t = base_type(e->type); @@ -2729,7 +2849,7 @@ gb_internal void generate_minimum_dependency_set_internal(Checker *c, Entity *st if (is_init) { - add_dependency_to_set(c, e); + add_to_set(c, e); array_add(&c->info.init_procedures, e); } } else if (e->flags & EntityFlag_Fini) { @@ -2764,7 +2884,7 @@ gb_internal void generate_minimum_dependency_set_internal(Checker *c, Entity *st } if (is_fini) { - add_dependency_to_set(c, e); + add_to_set(c, e); array_add(&c->info.fini_procedures, e); } } @@ -2781,7 +2901,7 @@ gb_internal void generate_minimum_dependency_set_internal(Checker *c, Entity *st Entity *e = entry.value; if (e != nullptr) { e->flags |= EntityFlag_Used; - add_dependency_to_set(c, e); + add_to_set(c, e); } } @@ -2796,16 +2916,11 @@ gb_internal void generate_minimum_dependency_set_internal(Checker *c, Entity *st } } else if (start != nullptr) { start->flags |= EntityFlag_Used; - add_dependency_to_set(c, start); + add_to_set(c, start); } } gb_internal void generate_minimum_dependency_set(Checker *c, Entity *start) { - isize entity_count = c->info.entities.count; - isize min_dep_set_cap = next_pow2_isize(entity_count*4); // empirically determined factor - - ptr_set_init(&c->info.minimum_dependency_set, min_dep_set_cap); - #define FORCE_ADD_RUNTIME_ENTITIES(condition, ...) do { \ if (condition) { \ String entities[] = {__VA_ARGS__}; \ @@ -2904,12 +3019,13 @@ gb_internal void generate_minimum_dependency_set(Checker *c, Entity *start) { generate_minimum_dependency_set_internal(c, start); + thread_pool_wait(); + #undef FORCE_ADD_RUNTIME_ENTITIES } -gb_internal bool is_entity_a_dependency(Entity *e) { - if (e == nullptr) return false; +gb_internal gb_inline bool is_entity_a_dependency(Entity *e) { switch (e->kind) { case Entity_Procedure: return true; @@ -2922,83 +3038,112 @@ gb_internal bool is_entity_a_dependency(Entity *e) { return false; } -gb_internal Array<EntityGraphNode *> generate_entity_dependency_graph(CheckerInfo *info, gbAllocator allocator) { - PtrMap<Entity *, EntityGraphNode *> M = {}; - map_init(&M, info->entities.count); - defer (map_destroy(&M)); +gb_internal Array<EntityGraphNode *> generate_entity_dependency_graph(CheckerInfo *info, Arena *arena) { + PtrMap<Entity *, EntityGraphNode *> M_procs = {}; + PtrMap<Entity *, EntityGraphNode *> M_vars = {}; + PtrMap<Entity *, EntityGraphNode *> M_other = {}; + + map_init(&M_procs, info->entities.count); + defer (map_destroy(&M_procs)); + + map_init(&M_vars, info->entities.count); + defer (map_destroy(&M_vars)); + + map_init(&M_other, info->entities.count); + defer (map_destroy(&M_other)); + for_array(i, info->entities) { Entity *e = info->entities[i]; - if (is_entity_a_dependency(e)) { - EntityGraphNode *n = gb_alloc_item(allocator, EntityGraphNode); - n->entity = e; - map_set(&M, e, n); + if (e == nullptr || !is_entity_a_dependency(e)) { + continue; + } + EntityGraphNode *n = arena_alloc_item<EntityGraphNode>(arena); + n->entity = e; + switch (e->kind) { + case Entity_Procedure: map_set(&M_procs, e, n); break; + case Entity_Variable: map_set(&M_vars, e, n); break; + default: map_set(&M_other, e, n); break; } } TIME_SECTION("generate_entity_dependency_graph: Calculate edges for graph M - Part 1"); // Calculate edges for graph M - for (auto const &entry : M) { + for (auto const &entry : M_procs) { EntityGraphNode *n = entry.value; Entity *e = n->entity; DeclInfo *decl = decl_info_of_entity(e); GB_ASSERT(decl != nullptr); - for (Entity *dep : decl->deps) { + FOR_PTR_SET(dep, decl->deps) { + GB_ASSERT(dep != nullptr); if (dep->flags & EntityFlag_Field) { continue; } - GB_ASSERT(dep != nullptr); - if (is_entity_a_dependency(dep)) { - EntityGraphNode *m = map_must_get(&M, dep); - entity_graph_node_set_add(&n->succ, m); - entity_graph_node_set_add(&m->pred, n); + if (!is_entity_a_dependency(dep)) { + continue; + } + EntityGraphNode *m = nullptr; + + switch (dep->kind) { + case Entity_Procedure: m = map_must_get(&M_procs, dep); break; + case Entity_Variable: m = map_must_get(&M_vars, dep); break; + default: m = map_must_get(&M_other, dep); break; } + entity_graph_node_set_add(&n->succ, m); + entity_graph_node_set_add(&m->pred, n); } } - TIME_SECTION("generate_entity_dependency_graph: Calculate edges for graph M - Part 2"); - auto G = array_make<EntityGraphNode *>(allocator, 0, M.count); + TIME_SECTION("generate_entity_dependency_graph: Calculate edges for graph M - Part 2a (init)"); - for (auto const &m_entry : M) { - auto *e = m_entry.key; + auto G = array_make<EntityGraphNode *>(arena_allocator(arena), 0, M_procs.count + M_vars.count + M_other.count); + + TIME_SECTION("generate_entity_dependency_graph: Calculate edges for graph M - Part 2b (procs)"); + + for (auto const &m_entry : M_procs) { EntityGraphNode *n = m_entry.value; - if (e->kind == Entity_Procedure) { - // Connect each pred 'p' of 'n' with each succ 's' and from - // the procedure node - for (EntityGraphNode *p : n->pred) { + // Connect each pred 'p' of 'n' with each succ 's' and from + // the procedure node + FOR_PTR_SET(p, n->pred) { + // Ignore self-cycles + if (p == n) { + continue; + } + // Each succ 's' of 'n' becomes a succ of 'p', and + // each pred 'p' of 'n' becomes a pred of 's' + FOR_PTR_SET(s, n->succ) { // Ignore self-cycles - if (p != n) { - // Each succ 's' of 'n' becomes a succ of 'p', and - // each pred 'p' of 'n' becomes a pred of 's' - for (EntityGraphNode *s : n->succ) { - // Ignore self-cycles - if (s != n) { - if (p->entity->kind == Entity_Procedure && - s->entity->kind == Entity_Procedure) { - // NOTE(bill, 2020-11-15): Only care about variable initialization ordering - // TODO(bill): This is probably wrong!!!! - continue; - } - // IMPORTANT NOTE/TODO(bill, 2020-11-15): These three calls take the majority of the - // the time to process - entity_graph_node_set_add(&p->succ, s); - entity_graph_node_set_add(&s->pred, p); - // Remove edge to 'n' - entity_graph_node_set_remove(&s->pred, n); - } - } - - // Remove edge to 'n' - entity_graph_node_set_remove(&p->succ, n); + if (s == n) { + continue; } + if (p->entity->kind == Entity_Procedure && + s->entity->kind == Entity_Procedure) { + // NOTE(bill, 2020-11-15): Only care about variable initialization ordering + // TODO(bill): This is probably wrong!!!! + continue; + } + // IMPORTANT NOTE/TODO(bill, 2020-11-15): These three calls take the majority of the + // the time to process + entity_graph_node_set_add(&p->succ, s); + entity_graph_node_set_add(&s->pred, p); + // Remove edge to 'n' + entity_graph_node_set_remove(&s->pred, n); } - } else if (e->kind == Entity_Variable) { - array_add(&G, n); + + // Remove edge to 'n' + entity_graph_node_set_remove(&p->succ, n); } } + TIME_SECTION("generate_entity_dependency_graph: Calculate edges for graph M - Part 2c (vars)"); + + for (auto const &m_entry : M_vars) { + EntityGraphNode *n = m_entry.value; + array_add(&G, n); + } + TIME_SECTION("generate_entity_dependency_graph: Dependency Count Checker"); for_array(i, G) { EntityGraphNode *n = G[i]; @@ -3082,19 +3227,17 @@ gb_internal Type *find_type_in_pkg(CheckerInfo *info, String const &pkg, String return e->type; } -gb_internal CheckerTypePath *new_checker_type_path() { - gbAllocator a = heap_allocator(); - auto *tp = gb_alloc_item(a, CheckerTypePath); - array_init(tp, a, 0, 16); +gb_internal CheckerTypePath *new_checker_type_path(gbAllocator allocator) { + auto *tp = gb_alloc_item(allocator, CheckerTypePath); + array_init(tp, allocator, 0, 16); return tp; } -gb_internal void destroy_checker_type_path(CheckerTypePath *tp) { +gb_internal void destroy_checker_type_path(CheckerTypePath *tp, gbAllocator allocator) { array_free(tp); - gb_free(heap_allocator(), tp); + gb_free(allocator, tp); } - gb_internal void check_type_path_push(CheckerContext *c, Entity *e) { GB_ASSERT(c->type_path != nullptr); GB_ASSERT(e != nullptr); @@ -3266,12 +3409,20 @@ gb_internal void init_core_map_type(Checker *c) { t_raw_map_ptr = alloc_type_pointer(t_raw_map); } +gb_internal void init_core_objc_c(Checker *c) { + if (build_context.metrics.os == TargetOs_darwin) { + t_objc_super = find_core_type(c, str_lit("objc_super")); + t_objc_super_ptr = alloc_type_pointer(t_objc_super); + } +} + gb_internal void init_preload(Checker *c) { init_core_type_info(c); init_mem_allocator(c); init_core_context(c); init_core_source_code_location(c); init_core_map_type(c); + init_core_objc_c(c); } gb_internal ExactValue check_decl_attribute_value(CheckerContext *c, Ast *value) { @@ -3430,7 +3581,7 @@ gb_internal DECL_ATTRIBUTE_PROC(proc_decl_attribute) { return true; } else if (name == "test") { if (value != nullptr) { - error(value, "'%.*s' expects no parameter, or a string literal containing \"file\" or \"package\"", LIT(name)); + error(value, "Expected no value for '%.*s'", LIT(name)); } ac->test = true; return true; @@ -3478,13 +3629,13 @@ gb_internal DECL_ATTRIBUTE_PROC(proc_decl_attribute) { return true; } else if (name == "init") { if (value != nullptr) { - error(value, "'%.*s' expects no parameter, or a string literal containing \"file\" or \"package\"", LIT(name)); + error(value, "Expected no value for '%.*s'", LIT(name)); } ac->init = true; return true; } else if (name == "fini") { if (value != nullptr) { - error(value, "'%.*s' expects no parameter, or a string literal containing \"file\" or \"package\"", LIT(name)); + error(value, "Expected no value for '%.*s'", LIT(name)); } ac->fini = true; return true; @@ -4849,7 +5000,7 @@ gb_internal void check_single_global_entity(Checker *c, Entity *e, DeclInfo *d) } gb_internal void check_all_global_entities(Checker *c) { - in_single_threaded_checker_stage = true; + in_single_threaded_checker_stage.store(true, std::memory_order_relaxed); // NOTE(bill): This must be single threaded // Don't bother trying @@ -4871,7 +5022,7 @@ gb_internal void check_all_global_entities(Checker *c) { } } - in_single_threaded_checker_stage = false; + in_single_threaded_checker_stage.store(false, std::memory_order_relaxed); } @@ -4960,26 +5111,22 @@ gb_internal void add_import_dependency_node(Checker *c, Ast *decl, PtrMap<AstPac error(token, "Unable to find package: %.*s", LIT(path)); exit_with_errors(); } - AstPackage *pkg = *found; - GB_ASSERT(pkg->scope != nullptr); + AstPackage *child_pkg = *found; + GB_ASSERT(child_pkg->scope != nullptr); - id->package = pkg; + id->package = child_pkg; - ImportGraphNode **found_node = nullptr; - ImportGraphNode *m = nullptr; - ImportGraphNode *n = nullptr; - - found_node = map_get(M, pkg); + ImportGraphNode **found_node = map_get(M, child_pkg); GB_ASSERT(found_node != nullptr); - m = *found_node; + ImportGraphNode *child = *found_node; found_node = map_get(M, parent_pkg); GB_ASSERT(found_node != nullptr); - n = *found_node; + ImportGraphNode *parent = *found_node; - import_graph_node_set_add(&n->succ, m); - import_graph_node_set_add(&m->pred, n); - ptr_set_add(&m->scope->imported, n->scope); + import_graph_node_set_add(&parent->succ, child); + import_graph_node_set_add(&child->pred, parent); + ptr_set_add(&parent->scope->imported, child->scope); case_end; case_ast_node(ws, WhenStmt, decl); @@ -5009,14 +5156,14 @@ gb_internal void add_import_dependency_node(Checker *c, Ast *decl, PtrMap<AstPac } } -gb_internal Array<ImportGraphNode *> generate_import_dependency_graph(Checker *c) { +gb_internal Array<ImportGraphNode *> generate_import_dependency_graph(Checker *c, gbAllocator allocator) { PtrMap<AstPackage *, ImportGraphNode *> M = {}; map_init(&M, 2*c->parser->packages.count); defer (map_destroy(&M)); for_array(i, c->parser->packages) { AstPackage *pkg = c->parser->packages[i]; - ImportGraphNode *n = import_graph_node_create(heap_allocator(), pkg); + ImportGraphNode *n = import_graph_node_create(allocator, pkg); map_set(&M, pkg, n); } @@ -5033,7 +5180,7 @@ gb_internal Array<ImportGraphNode *> generate_import_dependency_graph(Checker *c } Array<ImportGraphNode *> G = {}; - array_init(&G, heap_allocator(), 0, M.count); + array_init(&G, allocator, 0, M.count); isize i = 0; for (auto const &entry : M) { @@ -5052,7 +5199,7 @@ struct ImportPathItem { Ast * decl; }; -gb_internal Array<ImportPathItem> find_import_path(Checker *c, AstPackage *start, AstPackage *end, PtrSet<AstPackage *> *visited) { +gb_internal Array<ImportPathItem> find_import_path(Checker *c, AstPackage *start, AstPackage *end, PtrSet<AstPackage *> *visited, gbAllocator allocator) { Array<ImportPathItem> empty_path = {}; if (ptr_set_update(visited, start)) { @@ -5086,11 +5233,11 @@ gb_internal Array<ImportPathItem> find_import_path(Checker *c, AstPackage *start ImportPathItem item = {pkg, decl}; if (pkg == end) { - auto path = array_make<ImportPathItem>(heap_allocator()); + auto path = array_make<ImportPathItem>(allocator); array_add(&path, item); return path; } - auto next_path = find_import_path(c, pkg, end, visited); + auto next_path = find_import_path(c, pkg, end, visited, allocator); if (next_path.count > 0) { array_add(&next_path, item); return next_path; @@ -5170,9 +5317,10 @@ gb_internal void check_add_import_decl(CheckerContext *ctx, Ast *decl) { GB_ASSERT(scope->flags&ScopeFlag_Pkg); - if (ptr_set_update(&parent_scope->imported, scope)) { - // error(token, "Multiple import of the same file within this scope"); - } + ptr_set_add(&parent_scope->imported, scope); + // if (ptr_set_update(&parent_scope->imported, scope)) { + // // error(token, "Multiple import of the same file within this scope"); + // } String import_name = path_to_entity_name(id->import_name.string, id->fullpath, false); if (is_blank_ident(import_name)) { @@ -5694,14 +5842,9 @@ gb_internal void check_export_entities(Checker *c) { } gb_internal void check_import_entities(Checker *c) { - Array<ImportGraphNode *> dep_graph = generate_import_dependency_graph(c); - defer ({ - for_array(i, dep_graph) { - import_graph_node_destroy(dep_graph[i], heap_allocator()); - } - array_free(&dep_graph); - }); + TEMPORARY_ALLOCATOR_GUARD(); + Array<ImportGraphNode *> dep_graph = generate_import_dependency_graph(c, temporary_allocator()); TIME_SECTION("check_import_entities - sort packages"); // NOTE(bill): Priority queue @@ -5711,8 +5854,7 @@ gb_internal void check_import_entities(Checker *c) { defer (ptr_set_destroy(&emitted)); Array<ImportGraphNode *> package_order = {}; - array_init(&package_order, heap_allocator(), 0, c->parser->packages.count); - defer (array_free(&package_order)); + array_init(&package_order, temporary_allocator(), 0, c->parser->packages.count); while (pq.queue.count > 0) { ImportGraphNode *n = priority_queue_pop(&pq); @@ -5720,11 +5862,12 @@ gb_internal void check_import_entities(Checker *c) { AstPackage *pkg = n->pkg; if (n->dep_count > 0) { + TEMPORARY_ALLOCATOR_GUARD(); + PtrSet<AstPackage *> visited = {}; defer (ptr_set_destroy(&visited)); - auto path = find_import_path(c, pkg, pkg, &visited); - defer (array_free(&path)); + auto path = find_import_path(c, pkg, pkg, &visited, temporary_allocator()); if (path.count > 1) { ImportPathItem item = path[path.count-1]; @@ -5739,7 +5882,7 @@ gb_internal void check_import_entities(Checker *c) { } } - for (ImportGraphNode *p : n->pred) { + FOR_PTR_SET(p, n->pred) { p->dep_count = gb_max(p->dep_count-1, 0); priority_queue_fix(&pq, p->index); } @@ -5842,9 +5985,9 @@ gb_internal void check_import_entities(Checker *c) { } -gb_internal Array<Entity *> find_entity_path(Entity *start, Entity *end, PtrSet<Entity *> *visited = nullptr); +gb_internal Array<Entity *> find_entity_path(Entity *start, Entity *end, gbAllocator allocator, PtrSet<Entity *> *visited = nullptr); -gb_internal bool find_entity_path_tuple(Type *tuple, Entity *end, PtrSet<Entity *> *visited, Array<Entity *> *path_) { +gb_internal bool find_entity_path_tuple(Type *tuple, Entity *end, gbAllocator allocator, PtrSet<Entity *> *visited, Array<Entity *> *path_) { GB_ASSERT(path_ != nullptr); if (tuple == nullptr) { return false; @@ -5856,14 +5999,15 @@ gb_internal bool find_entity_path_tuple(Type *tuple, Entity *end, PtrSet<Entity if (var_decl == nullptr) { continue; } - for (Entity *dep : var_decl->deps) { + + FOR_PTR_SET(dep, var_decl->deps) { if (dep == end) { - auto path = array_make<Entity *>(heap_allocator()); + auto path = array_make<Entity *>(allocator); array_add(&path, dep); *path_ = path; return true; } - auto next_path = find_entity_path(dep, end, visited); + auto next_path = find_entity_path(dep, end, allocator, visited); if (next_path.count > 0) { array_add(&next_path, dep); *path_ = next_path; @@ -5875,7 +6019,7 @@ gb_internal bool find_entity_path_tuple(Type *tuple, Entity *end, PtrSet<Entity return false; } -gb_internal Array<Entity *> find_entity_path(Entity *start, Entity *end, PtrSet<Entity *> *visited) { +gb_internal Array<Entity *> find_entity_path(Entity *start, Entity *end, gbAllocator allocator, PtrSet<Entity *> *visited) { PtrSet<Entity *> visited_ = {}; bool made_visited = false; if (visited == nullptr) { @@ -5899,20 +6043,20 @@ gb_internal Array<Entity *> find_entity_path(Entity *start, Entity *end, PtrSet< GB_ASSERT(t->kind == Type_Proc); Array<Entity *> path = {}; - if (find_entity_path_tuple(t->Proc.params, end, visited, &path)) { + if (find_entity_path_tuple(t->Proc.params, end, allocator, visited, &path)) { return path; } - if (find_entity_path_tuple(t->Proc.results, end, visited, &path)) { + if (find_entity_path_tuple(t->Proc.results, end, allocator, visited, &path)) { return path; } } else { - for (Entity *dep : decl->deps) { + FOR_PTR_SET(dep, decl->deps) { if (dep == end) { - auto path = array_make<Entity *>(heap_allocator()); + auto path = array_make<Entity *>(allocator); array_add(&path, dep); return path; } - auto next_path = find_entity_path(dep, end, visited); + auto next_path = find_entity_path(dep, end, allocator, visited); if (next_path.count > 0) { array_add(&next_path, dep); return next_path; @@ -5928,13 +6072,10 @@ gb_internal void calculate_global_init_order(Checker *c) { CheckerInfo *info = &c->info; TIME_SECTION("calculate_global_init_order: generate entity dependency graph"); - Array<EntityGraphNode *> dep_graph = generate_entity_dependency_graph(info, heap_allocator()); - defer ({ - for_array(i, dep_graph) { - entity_graph_node_destroy(dep_graph[i], heap_allocator()); - } - array_free(&dep_graph); - }); + Arena *temporary_arena = get_arena(ThreadArena_Temporary); + ArenaTempGuard temporary_arena_guard(temporary_arena); + + Array<EntityGraphNode *> dep_graph = generate_entity_dependency_graph(info, temporary_arena); TIME_SECTION("calculate_global_init_order: priority queue create"); // NOTE(bill): Priority queue @@ -5949,8 +6090,8 @@ gb_internal void calculate_global_init_order(Checker *c) { Entity *e = n->entity; if (n->dep_count > 0) { - auto path = find_entity_path(e, e); - defer (array_free(&path)); + TEMPORARY_ALLOCATOR_GUARD(); + auto path = find_entity_path(e, e, temporary_allocator()); if (path.count > 0) { Entity *e = path[0]; @@ -5963,7 +6104,7 @@ gb_internal void calculate_global_init_order(Checker *c) { } } - for (EntityGraphNode *p : n->pred) { + FOR_PTR_SET(p, n->pred) { p->dep_count -= 1; p->dep_count = gb_max(p->dep_count, 0); priority_queue_fix(&pq, p->index); @@ -6067,7 +6208,7 @@ gb_internal bool check_proc_info(Checker *c, ProcInfo *pi, UntypedExprInfoMap *u switch (pi->decl->proc_checked_state.load()) { case ProcCheckedState_InProgress: if (e) { - GB_ASSERT(global_procedure_body_in_worker_queue.load()); + GB_ASSERT(global_procedure_body_in_worker_queue.load() != 0); } return false; case ProcCheckedState_Checked: @@ -6156,7 +6297,7 @@ gb_internal bool check_proc_info(Checker *c, ProcInfo *pi, UntypedExprInfoMap *u add_untyped_expressions(&c->info, ctx.untyped); rw_mutex_shared_lock(&ctx.decl->deps_mutex); - for (Entity *dep : ctx.decl->deps) { + FOR_PTR_SET(dep, ctx.decl->deps) { if (dep && dep->kind == Entity_Procedure && (dep->flags & EntityFlag_ProcBodyChecked) == 0) { check_procedure_later_from_entity(c, dep, NULL); @@ -6185,8 +6326,10 @@ gb_internal void check_unchecked_bodies(Checker *c) { // use the `procs_to_check` array global_procedure_body_in_worker_queue = false; - for (Entity *e : c->info.minimum_dependency_set) { - check_procedure_later_from_entity(c, e, "check_unchecked_bodies"); + for (Entity *e : c->info.entities) { + if (e->min_dep_count.load(std::memory_order_relaxed) > 0) { + check_procedure_later_from_entity(c, e, "check_unchecked_bodies"); + } } if (!global_procedure_body_in_worker_queue) { @@ -6209,8 +6352,9 @@ gb_internal void check_safety_all_procedures_for_unchecked(Checker *c) { defer (map_destroy(&untyped)); - for_array(i, c->info.all_procedures) { - ProcInfo *pi = c->info.all_procedures[i]; + array_reserve(&c->info.all_procedures, c->info.all_procedures_queue.count.load()); + + for (ProcInfo *pi = nullptr; mpsc_dequeue(&c->info.all_procedures_queue, &pi); /**/) { GB_ASSERT(pi != nullptr); GB_ASSERT(pi->decl != nullptr); Entity *e = pi->decl->entity; @@ -6225,6 +6369,8 @@ gb_internal void check_safety_all_procedures_for_unchecked(Checker *c) { consume_proc_info(c, pi, &untyped); } } + + array_add(&c->info.all_procedures, pi); } } @@ -6319,7 +6465,7 @@ gb_internal WORKER_TASK_PROC(check_proc_info_worker_proc) { gb_internal void check_init_worker_data(Checker *c) { u32 thread_count = cast(u32)global_thread_pool.threads.count; - check_procedure_bodies_worker_data = gb_alloc_array(permanent_allocator(), CheckProcedureBodyWorkerData, thread_count); + check_procedure_bodies_worker_data = permanent_alloc_array<CheckProcedureBodyWorkerData>(thread_count); for (isize i = 0; i < thread_count; i++) { check_procedure_bodies_worker_data[i].c = c; @@ -6381,7 +6527,7 @@ gb_internal Type *tuple_to_pointers(Type *ot) { Type *t = alloc_type_tuple(); - t->Tuple.variables = slice_make<Entity *>(heap_allocator(), ot->Tuple.variables.count); + t->Tuple.variables = permanent_slice_make<Entity *>(ot->Tuple.variables.count); Scope *scope = nullptr; for_array(i, t->Tuple.variables) { @@ -6887,9 +7033,11 @@ gb_internal void check_objc_context_provider_procedures(Checker *c) { } } -gb_internal void check_unique_package_names(Checker *c) { +gb_internal bool check_unique_package_names(Checker *c) { ERROR_BLOCK(); + bool ok = true; + StringMap<AstPackage *> pkgs = {}; // Key: package name string_map_init(&pkgs, 2*c->info.packages.count); defer (string_map_destroy(&pkgs)); @@ -6914,6 +7062,7 @@ gb_internal void check_unique_package_names(Checker *c) { continue; } + ok = false; begin_error_block(); error(curr, "Duplicate declaration of 'package %.*s'", LIT(name)); @@ -6936,6 +7085,8 @@ gb_internal void check_unique_package_names(Checker *c) { end_error_block(); } + + return ok; } gb_internal void check_add_entities_from_queues(Checker *c) { @@ -6960,6 +7111,7 @@ gb_internal void check_merge_queues_into_arrays(Checker *c) { } check_add_entities_from_queues(c); check_add_definitions_from_queues(c); + thread_pool_wait(); } gb_internal GB_COMPARE_PROC(init_procedures_cmp) { @@ -7014,17 +7166,23 @@ gb_internal void check_sort_init_and_fini_procedures(Checker *c) { } gb_internal void add_type_info_for_type_definitions(Checker *c) { - for_array(i, c->info.definitions) { - Entity *e = c->info.definitions[i]; + for (Entity *e : c->info.definitions) { if (e->kind == Entity_TypeName && e->type != nullptr && is_type_typed(e->type)) { + #if 0 i64 align = type_align_of(e->type); - if (align > 0 && ptr_set_exists(&c->info.minimum_dependency_set, e)) { + if (align > 0 && e->min_dep_count.load(std::memory_order_relaxed) > 0) { add_type_info_type(&c->builtin_ctx, e->type); } + #else + if (e->min_dep_count.load(std::memory_order_relaxed) > 0) { + add_type_info_type(&c->builtin_ctx, e->type); + } + #endif } } } +#if 0 gb_internal void check_walk_all_dependencies(DeclInfo *decl) { if (decl == nullptr) { return; @@ -7046,9 +7204,116 @@ gb_internal void check_update_dependency_tree_for_procedures(Checker *c) { check_walk_all_dependencies(decl); } } +#else +gb_internal void check_walk_all_dependencies(DeclInfo *decl); + +gb_internal WORKER_TASK_PROC(check_walk_all_dependencies_worker_proc) { + if (data == nullptr) { + return 0; + } + DeclInfo *decl = cast(DeclInfo *)data; + + for (DeclInfo *child = decl->next_child; child != nullptr; child = child->next_sibling) { + thread_pool_add_task(check_walk_all_dependencies_worker_proc, child); + check_walk_all_dependencies(child); + } + + add_deps_from_child_to_parent(decl); + return 0; +} + +gb_internal void check_walk_all_dependencies(DeclInfo *decl) { + if (decl != nullptr) { + thread_pool_add_task(check_walk_all_dependencies_worker_proc, decl); + } +} + +gb_internal void check_update_dependency_tree_for_procedures(Checker *c) { + mutex_lock(&c->nested_proc_lits_mutex); + for (DeclInfo *decl : c->nested_proc_lits) { + check_walk_all_dependencies(decl); + } + mutex_unlock(&c->nested_proc_lits_mutex); + for (Entity *e : c->info.entities) { + DeclInfo *decl = e->decl_info; + check_walk_all_dependencies(decl); + } + + thread_pool_wait(); +} +#endif + +gb_internal WORKER_TASK_PROC(check_scope_usage_file_worker) { + Checker *c = global_checker_ptr.load(std::memory_order_relaxed); + AstFile *f = cast(AstFile *)data; + u64 vet_flags = ast_file_vet_flags(f); + check_scope_usage(c, f->scope, vet_flags); + return 0; +} + +gb_internal WORKER_TASK_PROC(check_scope_usage_pkg_worker) { + Checker *c = global_checker_ptr.load(std::memory_order_relaxed); + AstPackage *pkg = cast(AstPackage *)data; + check_scope_usage_internal(c, pkg->scope, 0, true); + return 0; +} + + + +gb_internal void check_all_scope_usages(Checker *c) { + for (auto const &entry : c->info.files) { + AstFile *f = entry.value; + thread_pool_add_task(check_scope_usage_file_worker, f); + } + for (auto const &entry : c->info.packages) { + AstPackage *pkg = entry.value; + thread_pool_add_task(check_scope_usage_pkg_worker, pkg); + } + + thread_pool_wait(); +} + + +gb_internal void check_for_type_cycles(Checker *c) { + // NOTE(bill): Check for illegal cyclic type declarations + for_array(i, c->info.definitions) { + Entity *e = c->info.definitions[i]; + if (e->kind != Entity_TypeName) { + continue; + } + if (e->type != nullptr && is_type_typed(e->type)) { + if (e->TypeName.is_type_alias) { + // Ignore for the time being + } else { + (void)type_align_of(e->type); + } + } + } +} + +gb_internal void check_for_inline_cycles(Checker *c) { + for_array(i, c->info.definitions) { + Entity *e = c->info.definitions[i]; + if (e->kind != Entity_Procedure) { + continue; + } + DeclInfo *decl = e->decl_info; + ast_node(pl, ProcLit, decl->proc_lit); + if (pl->inlining == ProcInlining_inline) { + FOR_PTR_SET(dep, decl->deps) { + if (dep == e) { + error(e->token, "Cannot inline recursive procedure '%.*s'", LIT(e->token.string)); + break; + } + } + } + } +} gb_internal void check_parsed_files(Checker *c) { + global_checker_ptr.store(c, std::memory_order_relaxed); + TIME_SECTION("map full filepaths to scope"); add_type_info_type(&c->builtin_ctx, t_invalid); @@ -7112,16 +7377,9 @@ gb_internal void check_parsed_files(Checker *c) { TIME_SECTION("add entities from procedure bodies"); check_merge_queues_into_arrays(c); - TIME_SECTION("check scope usage"); - for (auto const &entry : c->info.files) { - AstFile *f = entry.value; - u64 vet_flags = ast_file_vet_flags(f); - check_scope_usage(c, f->scope, vet_flags); - } - for (auto const &entry : c->info.packages) { - AstPackage *pkg = entry.value; - check_scope_usage_internal(c, pkg->scope, 0, true); - } + TIME_SECTION("check all scope usages"); + check_all_scope_usages(c); + TIME_SECTION("add basic type information"); // Add "Basic" type information @@ -7134,29 +7392,11 @@ gb_internal void check_parsed_files(Checker *c) { } check_merge_queues_into_arrays(c); - TIME_SECTION("check for type cycles and inline cycles"); - // NOTE(bill): Check for illegal cyclic type declarations - for_array(i, c->info.definitions) { - Entity *e = c->info.definitions[i]; - if (e->kind == Entity_TypeName && e->type != nullptr && is_type_typed(e->type)) { - if (e->TypeName.is_type_alias) { - // Ignore for the time being - } else { - (void)type_align_of(e->type); - } - } else if (e->kind == Entity_Procedure) { - DeclInfo *decl = e->decl_info; - ast_node(pl, ProcLit, decl->proc_lit); - if (pl->inlining == ProcInlining_inline) { - for (Entity *dep : decl->deps) { - if (dep == e) { - error(e->token, "Cannot inline recursive procedure '%.*s'", LIT(e->token.string)); - break; - } - } - } - } - } + TIME_SECTION("check for type cycles"); + check_for_type_cycles(c); + + TIME_SECTION("check for inline cycles"); + check_for_inline_cycles(c); TIME_SECTION("check deferred procedures"); check_deferred_procedures(c); @@ -7181,11 +7421,9 @@ gb_internal void check_parsed_files(Checker *c) { check_unchecked_bodies(c); TIME_SECTION("check #soa types"); - check_merge_queues_into_arrays(c); - thread_pool_wait(); - TIME_SECTION("update minimum dependency set"); + TIME_SECTION("update minimum dependency set again"); generate_minimum_dependency_set_internal(c, c->info.entry_point); // NOTE(laytan): has to be ran after generate_minimum_dependency_set, @@ -7231,7 +7469,7 @@ gb_internal void check_parsed_files(Checker *c) { debugf("Total Procedure Bodies Checked: %td\n", total_bodies_checked.load(std::memory_order_relaxed)); TIME_SECTION("check unique package names"); - check_unique_package_names(c); + bool package_names_are_unique = check_unique_package_names(c); TIME_SECTION("sanity checks"); check_merge_queues_into_arrays(c); @@ -7250,7 +7488,6 @@ gb_internal void check_parsed_files(Checker *c) { TIME_SECTION("add untyped expression values"); - // Add untyped expression values for (UntypedExprInfo u = {}; mpsc_dequeue(&c->global_untyped_queue, &u); /**/) { GB_ASSERT(u.expr != nullptr && u.info != nullptr); if (is_type_typed(u.info->type)) { @@ -7261,9 +7498,10 @@ gb_internal void check_parsed_files(Checker *c) { TIME_SECTION("initialize and check for collisions in type info array"); { + TEMPORARY_ALLOCATOR_GUARD(); + Array<TypeInfoPair> type_info_types; // sorted after filled - array_init(&type_info_types, heap_allocator()); - defer (array_free(&type_info_types)); + array_init(&type_info_types, temporary_allocator()); for (auto const &tt : c->info.min_dep_type_info_set) { array_add(&type_info_types, tt); @@ -7288,7 +7526,8 @@ gb_internal void check_parsed_files(Checker *c) { c->info.type_info_types_hash_map[index] = tt; bool exists = map_set_if_not_previously_exists(&c->info.min_dep_type_info_index_map, tt.hash, index); - if (exists) { + // Because we've already written a nice error about a duplicate package declaration, skip this panic if the package names aren't unique. + if (package_names_are_unique && exists) { for (auto const &entry : c->info.min_dep_type_info_index_map) { if (entry.key != tt.hash) { continue; diff --git a/src/checker.hpp b/src/checker.hpp index 58ac8beb5..bda7b2746 100644 --- a/src/checker.hpp +++ b/src/checker.hpp @@ -209,7 +209,7 @@ struct DeclInfo { Scope * scope; - Entity *entity; + std::atomic<Entity *> entity; Ast * decl_node; Ast * type_expr; @@ -218,6 +218,8 @@ struct DeclInfo { Ast * proc_lit; // Ast_ProcLit Type * gen_proc_type; // Precalculated + Entity * para_poly_original; + bool is_using; bool where_clauses_evaluated; bool foreign_require_results; @@ -309,11 +311,12 @@ struct EntityGraphNode; typedef PtrSet<EntityGraphNode *> EntityGraphNodeSet; struct EntityGraphNode { - Entity * entity; // Procedure, Variable, Constant + Entity *entity; // Procedure, Variable, Constant + EntityGraphNodeSet pred; EntityGraphNodeSet succ; - isize index; // Index in array/queue - isize dep_count; + isize index; // Index in array/queue + isize dep_count; }; @@ -448,9 +451,11 @@ struct CheckerInfo { AstPackage * init_package; Scope * init_scope; Entity * entry_point; - PtrSet<Entity *> minimum_dependency_set; - BlockingMutex minimum_dependency_type_info_mutex; + + RwMutex minimum_dependency_type_info_mutex; PtrMap</*type info hash*/u64, /*min dep index*/isize> min_dep_type_info_index_map; + + RWSpinLock min_dep_type_info_set_mutex; TypeSet min_dep_type_info_set; Array<TypeInfoPair> type_info_types_hash_map; // 2 * type_info_types.count @@ -477,8 +482,6 @@ struct CheckerInfo { RecursiveMutex lazy_mutex; // Mutex required for lazy type checking of specific files - BlockingMutex gen_types_mutex; - PtrMap<Type *, GenTypesData *> gen_types; // BlockingMutex type_info_mutex; // NOT recursive // Array<TypeInfoPair> type_info_types; @@ -514,7 +517,7 @@ struct CheckerInfo { BlockingMutex load_file_mutex; StringMap<LoadFileCache *> load_file_cache; - BlockingMutex all_procedures_mutex; + MPSCQueue<ProcInfo *> all_procedures_queue; Array<ProcInfo *> all_procedures; BlockingMutex instrumentation_mutex; @@ -622,12 +625,12 @@ gb_internal Entity *entity_of_node(Ast *expr); gb_internal Entity *scope_lookup_current(Scope *s, String const &name); -gb_internal Entity *scope_lookup (Scope *s, String const &name); -gb_internal void scope_lookup_parent (Scope *s, String const &name, Scope **scope_, Entity **entity_); +gb_internal Entity *scope_lookup (Scope *s, String const &name, u32 hash=0); +gb_internal void scope_lookup_parent (Scope *s, String const &name, Scope **scope_, Entity **entity_, u32 hash=0); gb_internal Entity *scope_insert (Scope *s, Entity *entity); -gb_internal void add_type_and_value (CheckerContext *c, Ast *expression, AddressingMode mode, Type *type, ExactValue const &value); +gb_internal void add_type_and_value (CheckerContext *c, Ast *expression, AddressingMode mode, Type *type, ExactValue const &value, bool use_mutex=true); gb_internal ExprInfo *check_get_expr_info (CheckerContext *c, Ast *expr); gb_internal void add_untyped (CheckerContext *c, Ast *expression, AddressingMode mode, Type *basic_type, ExactValue const &value); gb_internal void add_entity_use (CheckerContext *c, Ast *identifier, Entity *entity); @@ -648,8 +651,8 @@ gb_internal void check_collect_entities(CheckerContext *c, Slice<Ast *> const &n gb_internal void check_collect_entities_from_when_stmt(CheckerContext *c, AstWhenStmt *ws); gb_internal void check_delayed_file_import_entity(CheckerContext *c, Ast *decl); -gb_internal CheckerTypePath *new_checker_type_path(); -gb_internal void destroy_checker_type_path(CheckerTypePath *tp); +gb_internal CheckerTypePath *new_checker_type_path(gbAllocator allocator); +gb_internal void destroy_checker_type_path(CheckerTypePath *tp, gbAllocator allocator); gb_internal void check_type_path_push(CheckerContext *c, Entity *e); gb_internal Entity *check_type_path_pop (CheckerContext *c); diff --git a/src/checker_builtin_procs.hpp b/src/checker_builtin_procs.hpp index c6071bf98..5b446cc1c 100644 --- a/src/checker_builtin_procs.hpp +++ b/src/checker_builtin_procs.hpp @@ -49,6 +49,11 @@ enum BuiltinProcId { BuiltinProc_constant_log2, + BuiltinProc_constant_floor, + BuiltinProc_constant_trunc, + BuiltinProc_constant_ceil, + BuiltinProc_constant_round, + BuiltinProc_transpose, BuiltinProc_outer_product, BuiltinProc_hadamard_product, @@ -56,6 +61,8 @@ enum BuiltinProcId { BuiltinProc_soa_struct, + BuiltinProc_concatenate, + BuiltinProc_alloca, BuiltinProc_cpu_relax, BuiltinProc_trap, @@ -251,6 +258,8 @@ BuiltinProc__type_simple_boolean_begin, BuiltinProc_type_is_quaternion, BuiltinProc_type_is_string, BuiltinProc_type_is_string16, + BuiltinProc_type_is_cstring, + BuiltinProc_type_is_cstring16, BuiltinProc_type_is_typeid, BuiltinProc_type_is_any, @@ -285,6 +294,8 @@ BuiltinProc__type_simple_boolean_begin, BuiltinProc_type_is_bit_set, BuiltinProc_type_is_simd_vector, BuiltinProc_type_is_matrix, + BuiltinProc_type_is_raw_union, + BuiltinProc_type_is_specialized_polymorphic_record, BuiltinProc_type_is_unspecialized_polymorphic_record, @@ -325,6 +336,7 @@ BuiltinProc__type_simple_boolean_end, BuiltinProc_type_polymorphic_record_parameter_value, BuiltinProc_type_is_subtype_of, + BuiltinProc_type_is_superset_of, BuiltinProc_type_field_index_of, @@ -354,6 +366,7 @@ BuiltinProc__type_end, BuiltinProc_objc_register_class, BuiltinProc_objc_ivar_get, BuiltinProc_objc_block, + BuiltinProc_objc_super, BuiltinProc_constant_utf16_cstring, @@ -413,7 +426,11 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("has_target_feature"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("constant_log2"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("constant_log2"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("constant_floor"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("constant_trunc"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("constant_ceil"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("constant_round"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("transpose"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("outer_product"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, @@ -422,6 +439,8 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("soa_struct"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, // Type + {STR_LIT("concatenate"), 2, true, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("alloca"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("cpu_relax"), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, @@ -606,6 +625,7 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT(""), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, {STR_LIT("type_is_boolean"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_is_bit_field"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_is_integer"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_is_rune"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_is_float"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, @@ -613,6 +633,8 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("type_is_quaternion"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_is_string"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_is_string16"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_is_cstring"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_is_cstring16"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_is_typeid"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_is_any"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, @@ -645,9 +667,9 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("type_is_enum"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_is_proc"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_is_bit_set"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("type_is_bit_field"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_is_simd_vector"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_is_matrix"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_is_raw_union"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_is_specialized_polymorphic_record"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_is_unspecialized_polymorphic_record"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, @@ -687,6 +709,7 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("type_polymorphic_record_parameter_value"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_is_subtype_of"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_is_superset_of"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics }, {STR_LIT("type_field_index_of"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, @@ -715,7 +738,8 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("objc_register_selector"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics, false, true}, {STR_LIT("objc_register_class"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics, false, true}, {STR_LIT("objc_ivar_get"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics, false, true}, - {STR_LIT("objc_block"), 1, true, Expr_Expr, BuiltinProcPkg_intrinsics, false, true}, + {STR_LIT("objc_block"), 1, true, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("objc_super"), 1, true, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("constant_utf16_cstring"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, diff --git a/src/common.cpp b/src/common.cpp index 5b007bf2c..d5fc1df4b 100644 --- a/src/common.cpp +++ b/src/common.cpp @@ -59,6 +59,11 @@ template <typename T> struct TypeIsPtrSizedInteger { enum {value = false}; }; template <> struct TypeIsPtrSizedInteger<isize> { enum {value = true}; }; template <> struct TypeIsPtrSizedInteger<usize> { enum {value = true}; }; +template <typename T> struct TypeIs64BitInteger { enum {value = false}; }; +template <> struct TypeIs64BitInteger<u64> { enum {value = true}; }; +template <> struct TypeIs64BitInteger<i64> { enum {value = true}; }; + + #include "unicode.cpp" #include "array.cpp" diff --git a/src/common_memory.cpp b/src/common_memory.cpp index 47b2796a9..addd43687 100644 --- a/src/common_memory.cpp +++ b/src/common_memory.cpp @@ -113,6 +113,13 @@ gb_internal void *arena_alloc(Arena *arena, isize min_size, isize alignment) { return ptr; } + +template <typename T> +gb_internal T *arena_alloc_item(Arena *arena) { + return cast(T *)arena_alloc(arena, gb_size_of(T), gb_align_of(T)); +} + + gb_internal void arena_free_all(Arena *arena) { while (arena->curr_block != nullptr) { MemoryBlock *free_block = arena->curr_block; @@ -346,7 +353,7 @@ gb_internal gbAllocator arena_allocator(Arena *arena) { gb_internal GB_ALLOCATOR_PROC(arena_allocator_proc) { void *ptr = nullptr; Arena *arena = cast(Arena *)allocator_data; - GB_ASSERT_NOT_NULL(arena); + GB_ASSERT(arena != nullptr); switch (type) { case gbAllocation_Alloc: @@ -394,6 +401,48 @@ gb_internal Arena *get_arena(ThreadArenaKind kind) { } +template <typename T> +gb_internal T *permanent_alloc_item() { + Arena *arena = get_arena(ThreadArena_Permanent); + return arena_alloc_item<T>(arena); +} + +template <typename T> +gb_internal T *permanent_alloc_array(isize count) { + Arena *arena = get_arena(ThreadArena_Permanent); + return cast(T *)arena_alloc(arena, gb_size_of(T)*count, gb_align_of(T)); +} + +template <typename T> +gb_internal Slice<T> permanent_slice_make(isize count) { + Arena *arena = get_arena(ThreadArena_Permanent); + T *data = cast(T *)arena_alloc(arena, gb_size_of(T)*count, gb_align_of(T)); + return {data, count}; +} + +template <typename T> +gb_internal T *temporary_alloc_item() { + Arena *arena = get_arena(ThreadArena_Temporary); + return arena_alloc_item<T>(arena); +} + +template <typename T> +gb_internal T *temporary_alloc_array(isize count) { + Arena *arena = get_arena(ThreadArena_Temporary); + return cast(T *)arena_alloc(arena, gb_size_of(T)*count, gb_align_of(T)); +} + +template <typename T> +gb_internal Slice<T> temporary_slice_make(isize count) { + Arena *arena = get_arena(ThreadArena_Temporary); + T *data = cast(T *)arena_alloc(arena, gb_size_of(T)*count, gb_align_of(T)); + return {data, count}; +} + + + + + gb_internal GB_ALLOCATOR_PROC(thread_arena_allocator_proc) { void *ptr = nullptr; @@ -432,15 +481,16 @@ gb_internal gbAllocator permanent_allocator() { } gb_internal gbAllocator temporary_allocator() { - return {thread_arena_allocator_proc, cast(void *)cast(uintptr)ThreadArena_Permanent}; + // return {thread_arena_allocator_proc, cast(void *)cast(uintptr)ThreadArena_Temporary}; + return permanent_allocator(); } #define TEMP_ARENA_GUARD(arena) ArenaTempGuard GB_DEFER_3(_arena_guard_){arena} -// #define TEMPORARY_ALLOCATOR_GUARD() -#define TEMPORARY_ALLOCATOR_GUARD() TEMP_ARENA_GUARD(get_arena(ThreadArena_Temporary)) +// #define TEMPORARY_ALLOCATOR_GUARD() TEMP_ARENA_GUARD(get_arena(ThreadArena_Temporary)) +#define TEMPORARY_ALLOCATOR_GUARD() #define PERMANENT_ALLOCATOR_GUARD() diff --git a/src/docs_format.cpp b/src/docs_format.cpp index 6378971d0..2235789d5 100644 --- a/src/docs_format.cpp +++ b/src/docs_format.cpp @@ -94,6 +94,7 @@ enum OdinDocTypeFlag_Struct : u32 { OdinDocTypeFlag_Struct_polymorphic = 1<<0, OdinDocTypeFlag_Struct_packed = 1<<1, OdinDocTypeFlag_Struct_raw_union = 1<<2, + OdinDocTypeFlag_Struct_all_or_none = 1<<3, }; enum OdinDocTypeFlag_Union : u32 { @@ -124,21 +125,76 @@ enum { struct OdinDocType { OdinDocTypeKind kind; + // Type_Kind specific used by some types + // Underlying flag types: + // .Basic - Type_Flags_Basic + // .Struct - Type_Flags_Struct + // .Union - Type_Flags_Union + // .Proc - Type_Flags_Proc + // .Bit_Set - Type_Flags_Bit_Set u32 flags; + + // Used by: + // .Basic + // .Named + // .Generic OdinDocString name; + + // Used By: .Struct, .Union OdinDocString custom_align; - // Used by some types + // Used by: + // .Array - 1 count: 0=len + // .Enumerated_Array - 1 count: 0=len + // .SOA_Struct_Fixed - 1 count: 0=len + // .Bit_Set - 2 count: 0=lower, 1=upper + // .Simd_Vector - 1 count: 0=len + // .Matrix - 2 count: 0=row_count, 1=column_count + // .Struct - <=2 count: 0=min_field_align, 1=max_field_align u32 elem_count_len; i64 elem_counts[OdinDocType_ElemsCap]; - // Each of these is esed by some types, not all + // Used by: .Procedures + // blank implies the "odin" calling convention OdinDocString calling_convention; + + // Used by: + // .Named - 1 type: 0=base type + // .Generic - <1 type: 0=specialization + // .Pointer - 1 type: 0=element + // .Array - 1 type: 0=element + // .Enumerated_Array - 2 types: 0=index and 1=element + // .Slice - 1 type: 0=element + // .Dynamic_Array - 1 type: 0=element + // .Map - 2 types: 0=key, 1=value + // .SOA_Struct_Fixed - 1 type: underlying SOA struct element + // .SOA_Struct_Slice - 1 type: underlying SOA struct element + // .SOA_Struct_Dynamic - 1 type: underlying SOA struct element + // .Union - 0+ types: variants + // .Enum - <1 type: 0=base type + // .Proc - 2 types: 0=parameters, 1=results + // .Bit_Set - <=2 types: 0=element type, 1=underlying type (Underlying_Type flag will be set) + // .Simd_Vector - 1 type: 0=element + // .Relative_Pointer - 2 types: 0=pointer type, 1=base integer + // .Multi_Pointer - 1 type: 0=element + // .Matrix - 1 type: 0=element + // .Soa_Pointer - 1 type: 0=element + // .Bit_Field - 1 type: 0=backing type OdinDocArray<OdinDocTypeIndex> types; + + // Used by: + // .Named - 1 field for the definition + // .Struct - fields + // .Enum - fields + // .Parameters - parameters (procedures only) OdinDocArray<OdinDocEntityIndex> entities; + + // Used By: .Struct, .Union OdinDocTypeIndex polmorphic_params; + // Used By: .Struct, .Union OdinDocArray<OdinDocString> where_clauses; - OdinDocArray<OdinDocString> tags; // struct field tags + // Used By: .Struct + OdinDocArray<OdinDocString> tags; }; struct OdinDocAttribute { diff --git a/src/docs_writer.cpp b/src/docs_writer.cpp index 1f2325980..3edd7da9d 100644 --- a/src/docs_writer.cpp +++ b/src/docs_writer.cpp @@ -620,6 +620,13 @@ gb_internal OdinDocTypeIndex odin_doc_type(OdinDocWriter *w, Type *type, bool ca if (type->Struct.is_polymorphic) { doc_type.flags |= OdinDocTypeFlag_Struct_polymorphic; } if (type->Struct.is_packed) { doc_type.flags |= OdinDocTypeFlag_Struct_packed; } if (type->Struct.is_raw_union) { doc_type.flags |= OdinDocTypeFlag_Struct_raw_union; } + if (type->Struct.is_all_or_none) { doc_type.flags |= OdinDocTypeFlag_Struct_all_or_none; } + + if (type->Struct.custom_min_field_align > 0 || type->Struct.custom_max_field_align > 0) { + doc_type.elem_count_len = 2; + doc_type.elem_counts[0] = cast(u32)gb_max(type->Struct.custom_min_field_align, 0); + doc_type.elem_counts[1] = cast(u32)gb_max(type->Struct.custom_max_field_align, 0); + } auto fields = array_make<OdinDocEntityIndex>(heap_allocator(), type->Struct.fields.count); defer (array_free(&fields)); diff --git a/src/entity.cpp b/src/entity.cpp index 6c0aa6ace..2b21fdcac 100644 --- a/src/entity.cpp +++ b/src/entity.cpp @@ -164,6 +164,7 @@ struct Entity { u64 id; std::atomic<u64> flags; std::atomic<EntityState> state; + std::atomic<i32> min_dep_count; Token token; Scope * scope; Type * type; @@ -233,6 +234,7 @@ struct Entity { } Variable; struct { Type * type_parameter_specialization; + Type * original_type_for_parapoly; String ir_mangled_name; bool is_type_alias; bool objc_is_implementation; @@ -249,6 +251,8 @@ struct Entity { String link_name; String link_prefix; String link_suffix; + String objc_selector_name; + Entity *objc_class; DeferredProcedure deferred_procedure; struct GenProcsData *gen_procs; @@ -264,6 +268,8 @@ struct Entity { bool is_anonymous : 1; bool no_sanitize_address : 1; bool no_sanitize_memory : 1; + bool is_objc_impl_or_import : 1; + bool is_objc_class_method : 1; } Procedure; struct { Array<Entity *> entities; @@ -347,7 +353,7 @@ gb_internal Entity *alloc_entity(EntityKind kind, Scope *scope, Token token, Typ entity->type = type; entity->id = 1 + global_entity_id.fetch_add(1); if (token.pos.file_id) { - entity->file = thread_safe_get_ast_file_from_id(token.pos.file_id); + entity->file = thread_unsafe_get_ast_file_from_id(token.pos.file_id); } return entity; } diff --git a/src/error.cpp b/src/error.cpp index 006d5ae8d..53bc01654 100644 --- a/src/error.cpp +++ b/src/error.cpp @@ -86,7 +86,7 @@ gb_internal char *token_pos_to_string(TokenPos const &pos); gb_internal bool set_file_path_string(i32 index, String const &path) { bool ok = false; GB_ASSERT(index >= 0); - mutex_lock(&global_error_collector.path_mutex); + // mutex_lock(&global_error_collector.path_mutex); mutex_lock(&global_files_mutex); if (index >= global_file_path_strings.count) { @@ -99,14 +99,14 @@ gb_internal bool set_file_path_string(i32 index, String const &path) { } mutex_unlock(&global_files_mutex); - mutex_unlock(&global_error_collector.path_mutex); + // mutex_unlock(&global_error_collector.path_mutex); return ok; } gb_internal bool thread_safe_set_ast_file_from_id(i32 index, AstFile *file) { bool ok = false; GB_ASSERT(index >= 0); - mutex_lock(&global_error_collector.path_mutex); + // mutex_lock(&global_error_collector.path_mutex); mutex_lock(&global_files_mutex); if (index >= global_files.count) { @@ -118,13 +118,13 @@ gb_internal bool thread_safe_set_ast_file_from_id(i32 index, AstFile *file) { ok = true; } mutex_unlock(&global_files_mutex); - mutex_unlock(&global_error_collector.path_mutex); + // mutex_unlock(&global_error_collector.path_mutex); return ok; } gb_internal String get_file_path_string(i32 index) { GB_ASSERT(index >= 0); - mutex_lock(&global_error_collector.path_mutex); + // mutex_lock(&global_error_collector.path_mutex); mutex_lock(&global_files_mutex); String path = {}; @@ -133,13 +133,13 @@ gb_internal String get_file_path_string(i32 index) { } mutex_unlock(&global_files_mutex); - mutex_unlock(&global_error_collector.path_mutex); + // mutex_unlock(&global_error_collector.path_mutex); return path; } gb_internal AstFile *thread_safe_get_ast_file_from_id(i32 index) { GB_ASSERT(index >= 0); - mutex_lock(&global_error_collector.path_mutex); + // mutex_lock(&global_error_collector.path_mutex); mutex_lock(&global_files_mutex); AstFile *file = nullptr; @@ -148,7 +148,18 @@ gb_internal AstFile *thread_safe_get_ast_file_from_id(i32 index) { } mutex_unlock(&global_files_mutex); - mutex_unlock(&global_error_collector.path_mutex); + // mutex_unlock(&global_error_collector.path_mutex); + return file; +} + + +// use AFTER PARSER +gb_internal AstFile *thread_unsafe_get_ast_file_from_id(i32 index) { + GB_ASSERT(index >= 0); + AstFile *file = nullptr; + if (index < global_files.count) { + file = global_files[index]; + } return file; } diff --git a/src/exact_value.cpp b/src/exact_value.cpp index f2aed84c2..f266b8b24 100644 --- a/src/exact_value.cpp +++ b/src/exact_value.cpp @@ -908,8 +908,8 @@ gb_internal ExactValue exact_binary_operator_value(TokenKind op, ExactValue x, E if (op != Token_Add) goto error; // NOTE(bill): How do you minimize this over allocation? - String sx = x.value_string; - String sy = y.value_string; + String16 sx = x.value_string16; + String16 sy = y.value_string16; isize len = sx.len+sy.len; u16 *data = gb_alloc_array(permanent_allocator(), u16, len); gb_memmove(data, sx.text, sx.len*gb_size_of(u16)); @@ -947,6 +947,8 @@ gb_internal gb_inline i32 cmp_f64(f64 a, f64 b) { return (a > b) - (a < b); } +gb_internal bool compare_exact_values_compound_lit(TokenKind op, ExactValue x, ExactValue y, bool *do_break_); + gb_internal bool compare_exact_values(TokenKind op, ExactValue x, ExactValue y) { match_exact_values(&x, &y); @@ -1055,9 +1057,24 @@ gb_internal bool compare_exact_values(TokenKind op, ExactValue x, ExactValue y) case Token_NotEq: return x.value_typeid != y.value_typeid; } break; + + case ExactValue_Compound: + if (op != Token_CmpEq && op != Token_NotEq) { + break; + } + + if (x.kind != y.kind) { + break; + } + bool do_break = false; + bool res = compare_exact_values_compound_lit(op, x, y, &do_break); + if (do_break) { + break; + } + return res; } - GB_PANIC("Invalid comparison"); + GB_PANIC("Invalid comparison: %d", x.kind); return false; } diff --git a/src/gb/gb.h b/src/gb/gb.h index ffc40b8ca..c52f63cec 100644 --- a/src/gb/gb.h +++ b/src/gb/gb.h @@ -714,13 +714,15 @@ extern "C++" { } while (0) #endif + +#if defined(DISABLE_ASSERT) +#define GB_ASSERT(cond) gb_unused(cond) +#endif + #ifndef GB_ASSERT #define GB_ASSERT(cond) GB_ASSERT_MSG(cond, NULL) #endif -#ifndef GB_ASSERT_NOT_NULL -#define GB_ASSERT_NOT_NULL(ptr) GB_ASSERT_MSG((ptr) != NULL, #ptr " must not be NULL") -#endif // NOTE(bill): Things that shouldn't happen with a message! #ifndef GB_PANIC @@ -3719,7 +3721,7 @@ gb_inline i32 gb_strcmp(char const *s1, char const *s2) { } gb_inline char *gb_strcpy(char *dest, char const *source) { - GB_ASSERT_NOT_NULL(dest); + GB_ASSERT(dest != NULL); if (source) { char *str = dest; while (*source) *str++ = *source++; @@ -3729,7 +3731,7 @@ gb_inline char *gb_strcpy(char *dest, char const *source) { gb_inline char *gb_strncpy(char *dest, char const *source, isize len) { - GB_ASSERT_NOT_NULL(dest); + GB_ASSERT(dest != NULL); if (source) { char *str = dest; while (len > 0 && *source) { @@ -3746,7 +3748,7 @@ gb_inline char *gb_strncpy(char *dest, char const *source, isize len) { gb_inline isize gb_strlcpy(char *dest, char const *source, isize len) { isize result = 0; - GB_ASSERT_NOT_NULL(dest); + GB_ASSERT(dest != NULL); if (source) { char const *source_start = source; char *str = dest; @@ -5636,7 +5638,7 @@ gbFileContents gb_file_read_contents(gbAllocator a, b32 zero_terminate, char con void gb_file_free_contents(gbFileContents *fc) { if (fc == NULL || fc->size == 0) return; - GB_ASSERT_NOT_NULL(fc->data); + GB_ASSERT(fc->data != NULL); gb_free(fc->allocator, fc->data); fc->data = NULL; fc->size = 0; @@ -5648,7 +5650,7 @@ void gb_file_free_contents(gbFileContents *fc) { gb_inline b32 gb_path_is_absolute(char const *path) { b32 result = false; - GB_ASSERT_NOT_NULL(path); + GB_ASSERT(path != NULL); #if defined(GB_SYSTEM_WINDOWS) result == (gb_strlen(path) > 2) && gb_char_is_alpha(path[0]) && @@ -5663,7 +5665,7 @@ gb_inline b32 gb_path_is_relative(char const *path) { return !gb_path_is_absolut gb_inline b32 gb_path_is_root(char const *path) { b32 result = false; - GB_ASSERT_NOT_NULL(path); + GB_ASSERT(path != NULL); #if defined(GB_SYSTEM_WINDOWS) result = gb_path_is_absolute(path) && (gb_strlen(path) == 3); #else @@ -5674,14 +5676,14 @@ gb_inline b32 gb_path_is_root(char const *path) { gb_inline char const *gb_path_base_name(char const *path) { char const *ls; - GB_ASSERT_NOT_NULL(path); + GB_ASSERT(path != NULL); ls = gb_char_last_occurence(path, '/'); return (ls == NULL) ? path : ls+1; } gb_inline char const *gb_path_extension(char const *path) { char const *ld; - GB_ASSERT_NOT_NULL(path); + GB_ASSERT(path != NULL); ld = gb_char_last_occurence(path, '.'); return (ld == NULL) ? NULL : ld+1; } diff --git a/src/linker.cpp b/src/linker.cpp index 41333a3c9..c2a3ee928 100644 --- a/src/linker.cpp +++ b/src/linker.cpp @@ -105,7 +105,7 @@ gb_internal i32 linker_stage(LinkerData *gen) { gb_printf_err("executing `orca sdk-path` did not produce output\n"); return 1; } - inputs = gb_string_append_fmt(inputs, " \"%s/orca-libc/lib/crt1.o\" \"%s/orca-libc/lib/libc.o\"", orca_sdk_path, orca_sdk_path); + inputs = gb_string_append_fmt(inputs, " \"%s/orca-libc/lib/crt1.o\" \"%s/orca-libc/lib/libc.a\"", orca_sdk_path, orca_sdk_path); extra_orca_flags = gb_string_append_fmt(extra_orca_flags, " -L \"%s/bin\" -lorca_wasm --export-dynamic", orca_sdk_path); } @@ -161,21 +161,32 @@ gb_internal i32 linker_stage(LinkerData *gen) { try_cross_linking:; #if defined(GB_SYSTEM_WINDOWS) + String section_name = str_lit("msvc-link"); bool is_windows = build_context.metrics.os == TargetOs_windows; #else + String section_name = str_lit("lld-link"); bool is_windows = false; #endif bool is_osx = build_context.metrics.os == TargetOs_darwin; + switch (build_context.linker_choice) { + case Linker_Default: break; + case Linker_lld: section_name = str_lit("lld-link"); break; + #if defined(GB_SYSTEM_LINUX) + case Linker_mold: section_name = str_lit("mold-link"); break; + #endif + #if defined(GB_SYSTEM_WINDOWS) + case Linker_radlink: section_name = str_lit("rad-link"); break; + #endif + default: + gb_printf_err("'%.*s' linker is not support for this platform\n", LIT(linker_choices[build_context.linker_choice])); + return 1; + } + + if (is_windows) { - String section_name = str_lit("msvc-link"); - switch (build_context.linker_choice) { - case Linker_Default: break; - case Linker_lld: section_name = str_lit("lld-link"); break; - case Linker_radlink: section_name = str_lit("rad-link"); break; - } timings_start_section(timings, section_name); gbString lib_str = gb_string_make(heap_allocator(), ""); @@ -281,7 +292,11 @@ try_cross_linking:; link_settings = gb_string_append_fmt(link_settings, " /NOENTRY"); } } else { - link_settings = gb_string_append_fmt(link_settings, " /ENTRY:mainCRTStartup"); + // For i386 with CRT, libcmt provides the entry point + // For other cases or no_crt, we need to specify the entry point + if (!(build_context.metrics.arch == TargetArch_i386 && !build_context.no_crt)) { + link_settings = gb_string_append_fmt(link_settings, " /ENTRY:mainCRTStartup"); + } } if (build_context.build_paths[BuildPath_Symbols].name != "") { @@ -419,7 +434,8 @@ try_cross_linking:; } } } else { - timings_start_section(timings, str_lit("ld-link")); + + timings_start_section(timings, section_name); int const ODIN_ANDROID_API_LEVEL = build_context.ODIN_ANDROID_API_LEVEL; @@ -952,6 +968,9 @@ try_cross_linking:; if (build_context.linker_choice == Linker_lld) { link_command_line = gb_string_append_fmt(link_command_line, " -fuse-ld=lld"); result = system_exec_command_line_app("lld-link", link_command_line); + } else if (build_context.linker_choice == Linker_mold) { + link_command_line = gb_string_append_fmt(link_command_line, " -fuse-ld=mold"); + result = system_exec_command_line_app("mold-link", link_command_line); } else { result = system_exec_command_line_app("ld-link", link_command_line); } diff --git a/src/llvm_abi.cpp b/src/llvm_abi.cpp index 8dbb8fa76..ec7c63b1a 100644 --- a/src/llvm_abi.cpp +++ b/src/llvm_abi.cpp @@ -144,7 +144,11 @@ gb_internal void lb_add_function_type_attributes(LLVMValueRef fn, lbFunctionType LLVMContextRef c = ft->ctx; LLVMAttributeRef noalias_attr = lb_create_enum_attribute(c, "noalias"); LLVMAttributeRef nonnull_attr = lb_create_enum_attribute(c, "nonnull"); +#if LLVM_VERSION_MAJOR >= 21 + LLVMAttributeRef nocapture_attr = lb_create_string_attribute(c, make_string_c("captures"), make_string_c("none")); +#else LLVMAttributeRef nocapture_attr = lb_create_enum_attribute(c, "nocapture"); +#endif unsigned arg_index = offset; for (unsigned i = 0; i < arg_count; i++) { @@ -522,6 +526,23 @@ namespace lbAbiAmd64Win64 { } }; + +gb_internal bool is_llvm_type_slice_like(LLVMTypeRef type) { + if (!lb_is_type_kind(type, LLVMStructTypeKind)) { + return false; + } + if (LLVMCountStructElementTypes(type) != 2) { + return false; + } + LLVMTypeRef fields[2] = {}; + LLVMGetStructElementTypes(type, fields); + if (!lb_is_type_kind(fields[0], LLVMPointerTypeKind)) { + return false; + } + return lb_is_type_kind(fields[1], LLVMIntegerTypeKind) && lb_sizeof(fields[1]) == 8; + +} + // NOTE(bill): I hate `namespace` in C++ but this is just because I don't want to prefix everything namespace lbAbiAmd64SysV { enum RegClass { @@ -652,23 +673,6 @@ namespace lbAbiAmd64SysV { return false; } - gb_internal bool is_llvm_type_slice_like(LLVMTypeRef type) { - if (!lb_is_type_kind(type, LLVMStructTypeKind)) { - return false; - } - if (LLVMCountStructElementTypes(type) != 2) { - return false; - } - LLVMTypeRef fields[2] = {}; - LLVMGetStructElementTypes(type, fields); - if (!lb_is_type_kind(fields[0], LLVMPointerTypeKind)) { - return false; - } - return lb_is_type_kind(fields[1], LLVMIntegerTypeKind) && lb_sizeof(fields[1]) == 8; - - } - - gb_internal bool is_aggregate(LLVMTypeRef type) { LLVMTypeKind kind = LLVMGetTypeKind(type); switch (kind) { diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index ff17e9c10..1cde65640 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -8,9 +8,15 @@ #endif #ifndef LLVM_IGNORE_VERIFICATION -#define LLVM_IGNORE_VERIFICATION 0 +#define LLVM_IGNORE_VERIFICATION build_context.internal_ignore_llvm_verification #endif +#ifndef LLVM_WEAK_MONOMORPHIZATION +#define LLVM_WEAK_MONOMORPHIZATION (USE_SEPARATE_MODULES && build_context.internal_weak_monomorphization) +#endif + +#define LLVM_SET_INTERNAL_WEAK_LINKAGE(value) LLVMSetLinkage(value, USE_SEPARATE_MODULES ? LLVMWeakAnyLinkage : LLVMInternalLinkage); + #include "llvm_backend.hpp" #include "llvm_abi.cpp" @@ -33,12 +39,10 @@ gb_internal String get_default_microarchitecture() { // x86-64-v2: (close to Nehalem) CMPXCHG16B, LAHF-SAHF, POPCNT, SSE3, SSE4.1, SSE4.2, SSSE3 // x86-64-v3: (close to Haswell) AVX, AVX2, BMI1, BMI2, F16C, FMA, LZCNT, MOVBE, XSAVE // x86-64-v4: AVX512F, AVX512BW, AVX512CD, AVX512DQ, AVX512VL - if (ODIN_LLVM_MINIMUM_VERSION_12) { - if (build_context.metrics.os == TargetOs_freestanding) { - default_march = str_lit("x86-64"); - } else { - default_march = str_lit("x86-64-v2"); - } + if (build_context.metrics.os == TargetOs_freestanding) { + default_march = str_lit("x86-64"); + } else { + default_march = str_lit("x86-64-v2"); } } else if (build_context.metrics.arch == TargetArch_riscv64) { default_march = str_lit("generic-rv64"); @@ -168,7 +172,7 @@ gb_internal void lb_correct_entity_linkage(lbGenerator *gen) { if (ec.e->kind == Entity_Variable) { other_global = LLVMGetNamedGlobal(ec.other_module->mod, ec.cname); if (other_global) { - LLVMSetLinkage(other_global, LLVMWeakAnyLinkage); + LLVM_SET_INTERNAL_WEAK_LINKAGE(other_global); if (!ec.e->Variable.is_export && !ec.e->Variable.is_foreign) { LLVMSetVisibility(other_global, LLVMHiddenVisibility); } @@ -176,7 +180,7 @@ gb_internal void lb_correct_entity_linkage(lbGenerator *gen) { } else if (ec.e->kind == Entity_Procedure) { other_global = LLVMGetNamedFunction(ec.other_module->mod, ec.cname); if (other_global) { - LLVMSetLinkage(other_global, LLVMWeakAnyLinkage); + LLVM_SET_INTERNAL_WEAK_LINKAGE(other_global); if (!ec.e->Procedure.is_export && !ec.e->Procedure.is_foreign) { LLVMSetVisibility(other_global, LLVMHiddenVisibility); } @@ -242,26 +246,12 @@ gb_internal String lb_internal_gen_name_from_type(char const *prefix, Type *type return proc_name; } - -gb_internal lbValue lb_equal_proc_for_type(lbModule *m, Type *type) { - type = base_type(type); - GB_ASSERT(is_type_comparable(type)); +gb_internal void lb_equal_proc_generate_body(lbModule *m, lbProcedure *p) { + Type *type = p->internal_gen_type; Type *pt = alloc_type_pointer(type); LLVMTypeRef ptr_type = lb_type(m, pt); - String proc_name = lb_internal_gen_name_from_type("__$equal", type); - lbProcedure **found = string_map_get(&m->gen_procs, proc_name); - lbProcedure *compare_proc = nullptr; - if (found) { - compare_proc = *found; - GB_ASSERT(compare_proc != nullptr); - return {compare_proc->value, compare_proc->type}; - } - - - lbProcedure *p = lb_create_dummy_procedure(m, proc_name, t_equal_proc); - string_map_set(&m->gen_procs, proc_name, p); lb_begin_procedure_body(p); LLVMSetLinkage(p->value, LLVMInternalLinkage); @@ -389,9 +379,29 @@ gb_internal lbValue lb_equal_proc_for_type(lbModule *m, Type *type) { } lb_end_procedure_body(p); +} - compare_proc = p; - return {compare_proc->value, compare_proc->type}; +gb_internal lbValue lb_equal_proc_for_type(lbModule *m, Type *type) { + type = base_type(type); + GB_ASSERT(is_type_comparable(type)); + + String proc_name = lb_internal_gen_name_from_type("__$equal", type); + lbProcedure **found = string_map_get(&m->gen_procs, proc_name); + if (found) { + lbProcedure *p = *found; + GB_ASSERT(p != nullptr); + return {p->value, p->type}; + } + + lbProcedure *p = lb_create_dummy_procedure(m, proc_name, t_equal_proc); + string_map_set(&m->gen_procs, proc_name, p); + p->internal_gen_type = type; + p->generate_body = lb_equal_proc_generate_body; + + // p->generate_body(m, p); + mpsc_enqueue(&m->procedures_to_generate, p); + + return {p->value, p->type}; } gb_internal lbValue lb_simple_compare_hash(lbProcedure *p, Type *type, lbValue data, lbValue seed) { @@ -620,6 +630,7 @@ gb_internal lbValue lb_hasher_proc_for_type(lbModule *m, Type *type) { #define LLVM_SET_VALUE_NAME(value, name) LLVMSetValueName2((value), (name), gb_count_of((name))-1); + gb_internal lbValue lb_map_get_proc_for_type(lbModule *m, Type *type) { GB_ASSERT(!build_context.dynamic_map_calls); type = base_type(type); @@ -634,6 +645,9 @@ gb_internal lbValue lb_map_get_proc_for_type(lbModule *m, Type *type) { lbProcedure *p = lb_create_dummy_procedure(m, proc_name, t_map_get_proc); string_map_set(&m->gen_procs, proc_name, p); + + p->internal_gen_type = type; + lb_begin_procedure_body(p); defer (lb_end_procedure_body(p)); @@ -1153,15 +1167,6 @@ gb_internal lbValue lb_dynamic_map_reserve(lbProcedure *p, lbValue const &map_pt return lb_emit_runtime_call(p, "__dynamic_map_reserve", args); } - -struct lbGlobalVariable { - lbValue var; - lbValue init; - DeclInfo *decl; - bool is_initialized; -}; - - gb_internal lbProcedure *lb_create_objc_names(lbModule *main_module) { if (build_context.metrics.os != TargetOs_darwin) { return nullptr; @@ -1412,8 +1417,21 @@ String lb_get_objc_type_encoding(Type *t, isize pointer_depth = 0) { return str_lit("?"); case Type_Proc: return str_lit("?"); - case Type_BitSet: - return lb_get_objc_type_encoding(t->BitSet.underlying, pointer_depth); + case Type_BitSet: { + Type *bitset_integer_type = t->BitSet.underlying; + if (!bitset_integer_type) { + switch (t->cached_size) { + case 1: bitset_integer_type = t_u8; break; + case 2: bitset_integer_type = t_u16; break; + case 4: bitset_integer_type = t_u32; break; + case 8: bitset_integer_type = t_u64; break; + case 16: bitset_integer_type = t_u128; break; + } + } + GB_ASSERT_MSG(bitset_integer_type, "Could not determine bit_set integer size for objc_type_encoding"); + + return lb_get_objc_type_encoding(bitset_integer_type, pointer_depth); + } case Type_SimdVector: { String type_str = lb_get_objc_type_encoding(t->SimdVector.elem, pointer_depth); @@ -1447,7 +1465,10 @@ String lb_get_objc_type_encoding(Type *t, isize pointer_depth = 0) { struct lbObjCGlobalClass { lbObjCGlobal g; - lbValue class_value; // Local registered class value + union { + lbValue class_value; // Local registered class value + lbAddr class_global; // Global class pointer. Placeholder for class implementations which are registered in order of definition. + }; }; gb_internal void lb_register_objc_thing( @@ -1477,44 +1498,43 @@ gb_internal void lb_register_objc_thing( LLVMSetInitializer(v.value, LLVMConstNull(t)); } - lbValue class_ptr = {}; - lbValue class_name = lb_const_value(m, t_cstring, exact_value_string(g.name)); - // If this class requires an implementation, save it for registration below. if (g.class_impl_type != nullptr) { // Make sure the superclass has been initialized before us - lbValue superclass_value = lb_const_nil(m, t_objc_Class); - auto &tn = g.class_impl_type->Named.type_name->TypeName; Type *superclass = tn.objc_superclass; if (superclass != nullptr) { auto& superclass_global = string_map_must_get(&class_map, superclass->Named.type_name->TypeName.objc_class_name); lb_register_objc_thing(handled, m, args, class_impls, class_map, p, superclass_global.g, call); - GB_ASSERT(superclass_global.class_value.value); - - superclass_value = superclass_global.class_value; + GB_ASSERT(superclass_global.class_global.addr.value); } - args.count = 3; - args[0] = superclass_value; - args[1] = class_name; - args[2] = lb_const_int(m, t_uint, 0); - class_ptr = lb_emit_runtime_call(p, "objc_allocateClassPair", args); + lbObjCGlobalClass impl_global = {}; + impl_global.g = g; + impl_global.class_global = addr; + + array_add(&class_impls, impl_global); - array_add(&class_impls, lbObjCGlobalClass{g, class_ptr}); + lbObjCGlobalClass* class_global = string_map_get(&class_map, g.name); + if (class_global != nullptr) { + class_global->class_global = addr; + } } else { + lbValue class_ptr = {}; + lbValue class_name = lb_const_value(m, t_cstring, exact_value_string(g.name)); + args.count = 1; args[0] = class_name; class_ptr = lb_emit_runtime_call(p, call, args); - } - lb_addr_store(p, addr, class_ptr); + lb_addr_store(p, addr, class_ptr); - lbObjCGlobalClass* class_global = string_map_get(&class_map, g.name); - if (class_global != nullptr) { - class_global->class_value = class_ptr; + lbObjCGlobalClass* class_global = string_map_get(&class_map, g.name); + if (class_global != nullptr) { + class_global->class_value = class_ptr; + } } } @@ -1577,7 +1597,7 @@ gb_internal void lb_finalize_objc_names(lbGenerator *gen, lbProcedure *p) { string_map_init(&global_class_map, (usize)gen->objc_classes.count); defer (string_map_destroy(&global_class_map)); - for (lbObjCGlobal g :referenced_classes) { + for (lbObjCGlobal g : referenced_classes) { string_map_set(&global_class_map, g.name, lbObjCGlobalClass{g}); } @@ -1624,9 +1644,36 @@ gb_internal void lb_finalize_objc_names(lbGenerator *gen, lbProcedure *p) { for (const auto &cd : class_impls) { auto &g = cd.g; - Type *class_type = g.class_impl_type; + + Type *class_type = g.class_impl_type; Type *class_ptr_type = alloc_type_pointer(class_type); - lbValue class_value = cd.class_value; + + // Begin class registration: create class pair and update global reference + lbValue class_value = {}; + + { + lbValue superclass_value = lb_const_nil(m, t_objc_Class); + + auto& tn = class_type->Named.type_name->TypeName; + Type *superclass = tn.objc_superclass; + + if (superclass != nullptr) { + auto& superclass_global = string_map_must_get(&global_class_map, superclass->Named.type_name->TypeName.objc_class_name); + superclass_value = superclass_global.class_value; + } + + args.count = 3; + args[0] = superclass_value; + args[1] = lb_const_value(m, t_cstring, exact_value_string(g.name)); + args[2] = lb_const_int(m, t_uint, 0); + class_value = lb_emit_runtime_call(p, "objc_allocateClassPair", args); + + lbObjCGlobalClass &mapped_global = string_map_must_get(&global_class_map, tn.objc_class_name); + lb_addr_store(p, mapped_global.class_global, class_value); + + mapped_global.class_value = class_value; + } + Type *ivar_type = class_type->Named.type_name->TypeName.objc_ivar; @@ -1646,7 +1693,6 @@ gb_internal void lb_finalize_objc_names(lbGenerator *gen, lbProcedure *p) { is_context_provider_ivar = ivar_type != nullptr && internal_check_is_assignable_to(contex_provider_self_named_type, ivar_type); } - Array<ObjcMethodData> *methods = map_get(&m->info->objc_method_implementations, class_type); if (!methods) { continue; @@ -1705,17 +1751,21 @@ gb_internal void lb_finalize_objc_names(lbGenerator *gen, lbProcedure *p) { wrapper_results_tuple, method_type->Proc.result_count, false, ProcCC_CDecl); lbProcedure *wrapper_proc = lb_create_dummy_procedure(m, proc_name, wrapper_proc_type); - lb_add_attribute_to_proc(wrapper_proc->module, wrapper_proc->value, "nounwind"); + + lb_add_function_type_attributes(wrapper_proc->value, lb_get_function_type(m, wrapper_proc_type), ProcCC_CDecl); // Emit the wrapper - LLVMSetLinkage(wrapper_proc->value, LLVMExternalLinkage); + // LLVMSetLinkage(wrapper_proc->value, LLVMInternalLinkage); + LLVMSetDLLStorageClass(wrapper_proc->value, LLVMDLLExportStorageClass); + lb_add_attribute_to_proc(wrapper_proc->module, wrapper_proc->value, "nounwind"); + lb_begin_procedure_body(wrapper_proc); { + LLVMValueRef context_addr = nullptr; if (method_type->Proc.calling_convention == ProcCC_Odin) { GB_ASSERT(context_provider); // Emit the get odin context call - get_context_args[0] = lbValue { wrapper_proc->raw_input_parameters[0], contex_provider_self_ptr_type, @@ -1731,44 +1781,58 @@ gb_internal void lb_finalize_objc_names(lbGenerator *gen, lbProcedure *p) { get_context_args[0] = lb_handle_objc_ivar_for_objc_object_pointer(wrapper_proc, real_self); } - lbValue context = lb_emit_call(wrapper_proc, context_provider_proc_value, get_context_args); - lbAddr context_addr = lb_addr(lb_address_from_load_or_generate_local(wrapper_proc, context)); - lb_push_context_onto_stack(wrapper_proc, context_addr); + lbValue context = lb_emit_call(wrapper_proc, context_provider_proc_value, get_context_args); + context_addr = lb_address_from_load(wrapper_proc, context).value;//lb_address_from_load_or_generate_local(wrapper_proc, context)); + // context_addr = LLVMGetOperand(context.value, 0); } + isize method_forward_arg_count = method_param_count + method_param_offset; + isize method_forward_return_arg_offset = 0; + auto raw_method_args = array_make<LLVMValueRef>(temporary_allocator(), 0, method_forward_arg_count+1); + + lbValue method_proc_value = lb_find_procedure_value_from_entity(m, md.proc_entity); + lbFunctionType* ft = lb_get_function_type(m, method_type); + bool has_return = false; + lbArgKind return_kind = {}; - auto method_call_args = array_make<lbValue>(temporary_allocator(), method_param_count + method_param_offset); + if (wrapper_results_tuple != nullptr) { + has_return = true; + return_kind = ft->ret.kind; + + if (return_kind == lbArg_Indirect) { + method_forward_return_arg_offset = 1; + array_add(&raw_method_args, wrapper_proc->return_ptr.addr.value); + } + } if (!md.ac.objc_is_class_method) { - method_call_args[0] = lbValue { - wrapper_proc->raw_input_parameters[0], - class_ptr_type, - }; + array_add(&raw_method_args, wrapper_proc->raw_input_parameters[method_forward_return_arg_offset]); } for (isize i = 0; i < method_param_count; i++) { - method_call_args[i+method_param_offset] = lbValue { - wrapper_proc->raw_input_parameters[i+2], - method_type->Proc.params->Tuple.variables[i+method_param_offset]->type, - }; + array_add(&raw_method_args, wrapper_proc->raw_input_parameters[i+2+method_forward_return_arg_offset]); + } + + if (method_type->Proc.calling_convention == ProcCC_Odin) { + array_add(&raw_method_args, context_addr); } - lbValue method_proc_value = lb_find_procedure_value_from_entity(m, md.proc_entity); // Call real procedure for method from here, passing the parameters expected, if any. - lbValue return_value = lb_emit_call(wrapper_proc, method_proc_value, method_call_args); + LLVMTypeRef fnp = lb_type_internal_for_procedures_raw(m, method_type); + LLVMValueRef ret_val_raw = LLVMBuildCall2(wrapper_proc->builder, fnp, method_proc_value.value, raw_method_args.data, (unsigned)raw_method_args.count, ""); - if (wrapper_results_tuple != nullptr) { - auto &result_var = method_type->Proc.results->Tuple.variables[0]; - return_value = lb_emit_conv(wrapper_proc, return_value, result_var->type); - lb_build_return_stmt_internal(wrapper_proc, return_value, result_var->token.pos); + if (has_return && return_kind != lbArg_Indirect) { + LLVMBuildRet(wrapper_proc->builder, ret_val_raw); + } + else { + LLVMBuildRetVoid(wrapper_proc->builder); } } lb_end_procedure_body(wrapper_proc); - // Add the method to the class String method_encoding = str_lit("v"); - // TODO (harold): Checker must ensure that objc_methods have a single return value or none! + GB_ASSERT(method_type->Proc.result_count <= 1); if (method_type->Proc.result_count != 0) { method_encoding = lb_get_objc_type_encoding(method_type->Proc.results->Tuple.variables[0]->type); @@ -1780,8 +1844,8 @@ gb_internal void lb_finalize_objc_names(lbGenerator *gen, lbProcedure *p) { method_encoding = concatenate_strings(temporary_allocator(), method_encoding, str_lit("#:")); } - for (isize i = method_param_offset; i < method_param_count; i++) { - Type *param_type = method_type->Proc.params->Tuple.variables[i]->type; + for (isize i = 0; i < method_param_count; i++) { + Type *param_type = method_type->Proc.params->Tuple.variables[i + method_param_offset]->type; String param_encoding = lb_get_objc_type_encoding(param_type); method_encoding = concatenate_strings(temporary_allocator(), method_encoding, param_encoding); @@ -1800,7 +1864,7 @@ gb_internal void lb_finalize_objc_names(lbGenerator *gen, lbProcedure *p) { args[2] = lbValue { wrapper_proc->value, wrapper_proc->type }; args[3] = lb_const_value(m, t_cstring, exact_value_string(method_encoding)); - // TODO(harold): Emit check BOOL result and panic if false. + // TODO(harold): Emit check BOOL result and panic if false? lb_emit_runtime_call(p, "class_addMethod", args); } // End methods @@ -1848,7 +1912,7 @@ gb_internal void lb_finalize_objc_names(lbGenerator *gen, lbProcedure *p) { // Defined in an external package, define it now in the main package LLVMTypeRef t = lb_type(m, t_int); - lbValue global{}; + lbValue global = {}; global.value = LLVMAddGlobal(m->mod, t, g.global_name); global.type = t_int_ptr; @@ -1900,12 +1964,16 @@ gb_internal void lb_verify_function(lbModule *m, lbProcedure *p, bool dump_ll=fa } gb_internal WORKER_TASK_PROC(lb_llvm_module_verification_worker_proc) { + if (LLVM_IGNORE_VERIFICATION) { + return 0; + } + char *llvm_error = nullptr; defer (LLVMDisposeMessage(llvm_error)); lbModule *m = cast(lbModule *)data; if (LLVMVerifyModule(m->mod, LLVMReturnStatusAction, &llvm_error)) { - gb_printf_err("LLVM Error:\n%s\n", llvm_error); + gb_printf_err("LLVM Error in module %s:\n%s\n", m->module_name, llvm_error); if (build_context.keep_temp_files) { TIME_SECTION("LLVM Print Module to File"); String filepath_ll = lb_filepath_ll_for_module(m); @@ -1921,118 +1989,153 @@ gb_internal WORKER_TASK_PROC(lb_llvm_module_verification_worker_proc) { return 0; } +gb_internal bool lb_init_global_var(lbModule *m, lbProcedure *p, Entity *e, Ast *init_expr, lbGlobalVariable &var) { + if (init_expr != nullptr) { + lbValue init = lb_build_expr(p, init_expr); + if (init.value == nullptr) { + LLVMTypeRef global_type = llvm_addr_type(p->module, var.var); + if (is_type_untyped_nil(init.type)) { + LLVMSetInitializer(var.var.value, LLVMConstNull(global_type)); + var.is_initialized = true; + if (e->Variable.is_rodata) { + LLVMSetGlobalConstant(var.var.value, true); + } + return true; + } + GB_PANIC("Invalid init value, got %s", expr_to_string(init_expr)); + } -gb_internal lbProcedure *lb_create_startup_runtime(lbModule *main_module, lbProcedure *objc_names, Array<lbGlobalVariable> &global_variables) { // Startup Runtime - Type *proc_type = alloc_type_proc(nullptr, nullptr, 0, nullptr, 0, false, ProcCC_Odin); + if (is_type_any(e->type)) { + var.init = init; + } else if (lb_is_const_or_global(init)) { + if (!var.is_initialized) { + if (is_type_proc(init.type)) { + init.value = LLVMConstPointerCast(init.value, lb_type(p->module, init.type)); + } + LLVMSetInitializer(var.var.value, init.value); + var.is_initialized = true; - lbProcedure *p = lb_create_dummy_procedure(main_module, str_lit(LB_STARTUP_RUNTIME_PROC_NAME), proc_type); - p->is_startup = true; - lb_add_attribute_to_proc(p->module, p->value, "optnone"); - lb_add_attribute_to_proc(p->module, p->value, "noinline"); + if (e->Variable.is_rodata) { + LLVMSetGlobalConstant(var.var.value, true); + } + return true; + } + } else { + var.init = init; + } + } - // Make sure shared libraries call their own runtime startup on Linux. - LLVMSetVisibility(p->value, LLVMHiddenVisibility); - LLVMSetLinkage(p->value, LLVMWeakAnyLinkage); + if (var.init.value != nullptr) { + GB_ASSERT(!var.is_initialized); + Type *t = type_deref(var.var.type); + + if (is_type_any(t)) { + // NOTE(bill): Edge case for 'any' type + Type *var_type = default_type(var.init.type); + gbString var_name = gb_string_make(permanent_allocator(), "__$global_any::"); + gbString e_str = string_canonical_entity_name(temporary_allocator(), e); + var_name = gb_string_append_length(var_name, e_str, gb_strlen(e_str)); + lbAddr g = lb_add_global_generated_with_name(m, var_type, {}, make_string_c(var_name)); + lb_addr_store(p, g, var.init); + lbValue gp = lb_addr_get_ptr(p, g); + + lbValue data = lb_emit_struct_ep(p, var.var, 0); + lbValue ti = lb_emit_struct_ep(p, var.var, 1); + lb_emit_store(p, data, lb_emit_conv(p, gp, t_rawptr)); + lb_emit_store(p, ti, lb_typeid(p->module, var_type)); + } else { + LLVMTypeRef vt = llvm_addr_type(p->module, var.var); + lbValue src0 = lb_emit_conv(p, var.init, t); + LLVMValueRef src = OdinLLVMBuildTransmute(p, src0.value, vt); + LLVMValueRef dst = var.var.value; + LLVMBuildStore(p->builder, src, dst); + } + + var.is_initialized = true; + } + return false; +} + +gb_internal void lb_create_startup_runtime_generate_body(lbModule *m, lbProcedure *p) { lb_begin_procedure_body(p); - lb_setup_type_info_data(main_module); + lb_setup_type_info_data(m); - if (objc_names) { - LLVMBuildCall2(p->builder, lb_type_internal_for_procedures_raw(main_module, objc_names->type), objc_names->value, nullptr, 0, ""); + if (p->objc_names) { + LLVMBuildCall2(p->builder, lb_type_internal_for_procedures_raw(m, p->objc_names->type), p->objc_names->value, nullptr, 0, ""); } + Type *dummy_type = alloc_type_proc(nullptr, nullptr, 0, nullptr, 0, false, ProcCC_Odin); + LLVMTypeRef raw_dummy_type = lb_type_internal_for_procedures_raw(m, dummy_type); - for (auto &var : global_variables) { + for (auto &var : *p->global_variables) { if (var.is_initialized) { continue; } - lbModule *entity_module = main_module; + lbModule *entity_module = m; Entity *e = var.decl->entity; GB_ASSERT(e->kind == Entity_Variable); e->code_gen_module = entity_module; - Ast *init_expr = var.decl->init_expr; - if (init_expr != nullptr) { - lbValue init = lb_build_expr(p, init_expr); - if (init.value == nullptr) { - LLVMTypeRef global_type = llvm_addr_type(p->module, var.var); - if (is_type_untyped_nil(init.type)) { - LLVMSetInitializer(var.var.value, LLVMConstNull(global_type)); - var.is_initialized = true; - - if (e->Variable.is_rodata) { - LLVMSetGlobalConstant(var.var.value, true); - } - continue; - } - GB_PANIC("Invalid init value, got %s", expr_to_string(init_expr)); - } - - if (is_type_any(e->type) || is_type_union(e->type)) { - var.init = init; - } else if (lb_is_const_or_global(init)) { - if (!var.is_initialized) { - if (is_type_proc(init.type)) { - init.value = LLVMConstPointerCast(init.value, lb_type(p->module, init.type)); - } - LLVMSetInitializer(var.var.value, init.value); - var.is_initialized = true; - if (e->Variable.is_rodata) { - LLVMSetGlobalConstant(var.var.value, true); - } - continue; - } - } else { - var.init = init; - } + if (init_expr == nullptr && var.init.value == nullptr) { + continue; } - if (var.init.value != nullptr) { - GB_ASSERT(!var.is_initialized); - Type *t = type_deref(var.var.type); - - if (is_type_any(t)) { - // NOTE(bill): Edge case for 'any' type - Type *var_type = default_type(var.init.type); - gbString var_name = gb_string_make(permanent_allocator(), "__$global_any::"); - gbString e_str = string_canonical_entity_name(temporary_allocator(), e); - var_name = gb_string_append_length(var_name, e_str, gb_strlen(e_str)); - lbAddr g = lb_add_global_generated_with_name(main_module, var_type, {}, make_string_c(var_name)); - lb_addr_store(p, g, var.init); - lbValue gp = lb_addr_get_ptr(p, g); - - lbValue data = lb_emit_struct_ep(p, var.var, 0); - lbValue ti = lb_emit_struct_ep(p, var.var, 1); - lb_emit_store(p, data, lb_emit_conv(p, gp, t_rawptr)); - lb_emit_store(p, ti, lb_typeid(p->module, var_type)); - } else { - LLVMTypeRef vt = llvm_addr_type(p->module, var.var); - lbValue src0 = lb_emit_conv(p, var.init, t); - LLVMValueRef src = OdinLLVMBuildTransmute(p, src0.value, vt); - LLVMValueRef dst = var.var.value; - LLVMBuildStore(p->builder, src, dst); - } + if (false && type_size_of(e->type) > 8) { + String ename = lb_get_entity_name(m, e); + gbString name = gb_string_make(permanent_allocator(), ""); + name = gb_string_appendc(name, "__$startup$"); + name = gb_string_append_length(name, ename.text, ename.len); - var.is_initialized = true; - } + lbProcedure *dummy = lb_create_dummy_procedure(m, make_string_c(name), dummy_type); + dummy->is_startup = true; + LLVMSetVisibility(dummy->value, LLVMHiddenVisibility); + LLVM_SET_INTERNAL_WEAK_LINKAGE(p->value); + lb_begin_procedure_body(dummy); + lb_init_global_var(m, dummy, e, init_expr, var); + lb_end_procedure_body(dummy); + LLVMValueRef context_ptr = lb_find_or_generate_context_ptr(p).addr.value; + LLVMValueRef cast_ctx = LLVMBuildBitCast(p->builder, context_ptr, LLVMPointerType(LLVMInt8TypeInContext(m->ctx), 0), ""); + LLVMBuildCall2(p->builder, raw_dummy_type, dummy->value, &cast_ctx, 1, ""); + } else { + lb_init_global_var(m, p, e, init_expr, var); + } } - CheckerInfo *info = main_module->gen->info; - + CheckerInfo *info = m->gen->info; + for (Entity *e : info->init_procedures) { - lbValue value = lb_find_procedure_value_from_entity(main_module, e); + lbValue value = lb_find_procedure_value_from_entity(m, e); lb_emit_call(p, value, {}, ProcInlining_none); } lb_end_procedure_body(p); +} + + +gb_internal lbProcedure *lb_create_startup_runtime(lbModule *main_module, lbProcedure *objc_names, Array<lbGlobalVariable> &global_variables) { // Startup Runtime + Type *proc_type = alloc_type_proc(nullptr, nullptr, 0, nullptr, 0, false, ProcCC_Odin); + + lbProcedure *p = lb_create_dummy_procedure(main_module, str_lit(LB_STARTUP_RUNTIME_PROC_NAME), proc_type); + p->is_startup = true; + lb_add_attribute_to_proc(p->module, p->value, "optnone"); + lb_add_attribute_to_proc(p->module, p->value, "noinline"); + + // Make sure shared libraries call their own runtime startup on Linux. + LLVMSetVisibility(p->value, LLVMHiddenVisibility); + LLVM_SET_INTERNAL_WEAK_LINKAGE(p->value); + + p->global_variables = &global_variables; + p->objc_names = objc_names; + + lb_create_startup_runtime_generate_body(main_module, p); - lb_verify_function(main_module, p); return p; } @@ -2046,7 +2149,7 @@ gb_internal lbProcedure *lb_create_cleanup_runtime(lbModule *main_module) { // C // Make sure shared libraries call their own runtime cleanup on Linux. LLVMSetVisibility(p->value, LLVMHiddenVisibility); - LLVMSetLinkage(p->value, LLVMWeakAnyLinkage); + LLVM_SET_INTERNAL_WEAK_LINKAGE(p->value); lb_begin_procedure_body(p); @@ -2073,7 +2176,7 @@ gb_internal WORKER_TASK_PROC(lb_generate_procedures_and_types_per_module) { for (Entity *e : m->global_procedures_to_create) { (void)lb_get_entity_name(m, e); - array_add(&m->procedures_to_generate, lb_create_procedure(m, e)); + mpsc_enqueue(&m->procedures_to_generate, lb_create_procedure(m, e)); } return 0; } @@ -2097,8 +2200,6 @@ gb_internal GB_COMPARE_PROC(llvm_global_entity_cmp) { } gb_internal void lb_create_global_procedures_and_types(lbGenerator *gen, CheckerInfo *info, bool do_threading) { - auto *min_dep_set = &info->minimum_dependency_set; - for (Entity *e : info->entities) { String name = e->token.string; Scope * scope = e->scope; @@ -2135,18 +2236,28 @@ gb_internal void lb_create_global_procedures_and_types(lbGenerator *gen, Checker } } - if (!polymorphic_struct && !ptr_set_exists(min_dep_set, e)) { + if (!polymorphic_struct && e->min_dep_count.load(std::memory_order_relaxed) == 0) { // NOTE(bill): Nothing depends upon it so doesn't need to be built continue; } + // if (!polymorphic_struct && !ptr_set_exists(min_dep_set, e)) { + // // NOTE(bill): Nothing depends upon it so doesn't need to be built + // continue; + // } + lbModule *m = &gen->default_module; if (USE_SEPARATE_MODULES) { - m = lb_module_of_entity(gen, e); + m = lb_module_of_entity(gen, e, m); } GB_ASSERT(m != nullptr); if (e->kind == Entity_Procedure) { + if (e->Procedure.is_foreign && e->Procedure.is_objc_impl_or_import) { + // Do not generate declarations for foreign Objective-C methods. These are called indirectly through the Objective-C runtime. + continue; + } + array_add(&m->global_procedures_to_create, e); } else if (e->kind == Entity_TypeName) { array_add(&m->global_types_to_create, e); @@ -2258,7 +2369,7 @@ gb_internal WORKER_TASK_PROC(lb_llvm_function_pass_per_module) { lb_llvm_function_pass_per_function_internal(m, m->gen->objc_names); } - for (lbProcedure *p : m->procedures_to_generate) { + MUTEX_GUARD_BLOCK(&m->generated_procedures_mutex) for (lbProcedure *p : m->generated_procedures) { if (p->body != nullptr) { // Build Procedure lbFunctionPassManagerKind pass_manager_kind = lbFunctionPassManager_default; if (p->flags & lbProcedureFlag_WithoutMemcpyPass) { @@ -2297,17 +2408,23 @@ gb_internal WORKER_TASK_PROC(lb_llvm_function_pass_per_module) { } +void lb_remove_unused_functions_and_globals(lbGenerator *gen) { + for (auto &entry : gen->modules) { + lbModule *m = entry.value; + lb_run_remove_unused_function_pass(m); + lb_run_remove_unused_globals_pass(m); + } +} + struct lbLLVMModulePassWorkerData { lbModule *m; LLVMTargetMachineRef target_machine; + bool do_threading; }; gb_internal WORKER_TASK_PROC(lb_llvm_module_pass_worker_proc) { auto wd = cast(lbLLVMModulePassWorkerData *)data; - lb_run_remove_unused_function_pass(wd->m); - lb_run_remove_unused_globals_pass(wd->m); - LLVMPassManagerRef module_pass_manager = LLVMCreatePassManager(); lb_populate_module_pass_manager(wd->target_machine, module_pass_manager, build_context.optimization_level); LLVMRunPassManager(module_pass_manager, wd->m->mod); @@ -2383,6 +2500,17 @@ gb_internal WORKER_TASK_PROC(lb_llvm_module_pass_worker_proc) { return 1; } #endif + + if (LLVM_IGNORE_VERIFICATION) { + return 0; + } + + if (wd->do_threading) { + thread_pool_add_task(lb_llvm_module_verification_worker_proc, wd->m); + } else { + lb_llvm_module_verification_worker_proc(wd->m); + } + return 0; } @@ -2390,8 +2518,7 @@ gb_internal WORKER_TASK_PROC(lb_llvm_module_pass_worker_proc) { gb_internal WORKER_TASK_PROC(lb_generate_procedures_worker_proc) { lbModule *m = cast(lbModule *)data; - for (isize i = 0; i < m->procedures_to_generate.count; i++) { - lbProcedure *p = m->procedures_to_generate[i]; + for (lbProcedure *p = nullptr; mpsc_dequeue(&m->procedures_to_generate, &p); /**/) { lb_generate_procedure(p->module, p); } return 0; @@ -2415,15 +2542,22 @@ gb_internal void lb_generate_procedures(lbGenerator *gen, bool do_threading) { gb_internal WORKER_TASK_PROC(lb_generate_missing_procedures_to_check_worker_proc) { lbModule *m = cast(lbModule *)data; - for (isize i = 0; i < m->missing_procedures_to_check.count; i++) { - lbProcedure *p = m->missing_procedures_to_check[i]; - debugf("Generate missing procedure: %.*s module %p\n", LIT(p->name), m); - lb_generate_procedure(m, p); + for (lbProcedure *p = nullptr; mpsc_dequeue(&m->missing_procedures_to_check, &p); /**/) { + if (!p->is_done.load(std::memory_order_relaxed)) { + debugf("Generate missing procedure: %.*s module %p\n", LIT(p->name), m); + lb_generate_procedure(m, p); + } + + for (lbProcedure *nested = nullptr; mpsc_dequeue(&m->procedures_to_generate, &nested); /**/) { + mpsc_enqueue(&m->missing_procedures_to_check, nested); + } } return 0; } gb_internal void lb_generate_missing_procedures(lbGenerator *gen, bool do_threading) { + isize retry_count = 0; +retry:; if (do_threading) { for (auto const &entry : gen->modules) { lbModule *m = entry.value; @@ -2438,6 +2572,20 @@ gb_internal void lb_generate_missing_procedures(lbGenerator *gen, bool do_thread lb_generate_missing_procedures_to_check_worker_proc(m); } } + + for (auto const &entry : gen->modules) { + lbModule *m = entry.value; + if (m->missing_procedures_to_check.count != 0) { + if (retry_count > gen->modules.count) { + GB_ASSERT(m->missing_procedures_to_check.count == 0); + } + + retry_count += 1; + goto retry; + } + GB_ASSERT(m->missing_procedures_to_check.count == 0); + GB_ASSERT(m->procedures_to_generate.count == 0); + } } gb_internal void lb_debug_info_complete_types_and_finalize(lbGenerator *gen) { @@ -2465,19 +2613,16 @@ gb_internal void lb_llvm_function_passes(lbGenerator *gen, bool do_threading) { } -gb_internal void lb_llvm_module_passes(lbGenerator *gen, bool do_threading) { +gb_internal void lb_llvm_module_passes_and_verification(lbGenerator *gen, bool do_threading) { if (do_threading) { for (auto const &entry : gen->modules) { lbModule *m = entry.value; auto wd = gb_alloc_item(permanent_allocator(), lbLLVMModulePassWorkerData); wd->m = m; wd->target_machine = m->target_machine; + wd->do_threading = true; - if (do_threading) { - thread_pool_add_task(lb_llvm_module_pass_worker_proc, wd); - } else { - lb_llvm_module_pass_worker_proc(wd); - } + thread_pool_add_task(lb_llvm_module_pass_worker_proc, wd); } thread_pool_wait(); } else { @@ -2486,6 +2631,7 @@ gb_internal void lb_llvm_module_passes(lbGenerator *gen, bool do_threading) { auto wd = gb_alloc_item(permanent_allocator(), lbLLVMModulePassWorkerData); wd->m = m; wd->target_machine = m->target_machine; + wd->do_threading = false; lb_llvm_module_pass_worker_proc(wd); } } @@ -2566,31 +2712,6 @@ gb_internal String lb_filepath_obj_for_module(lbModule *m) { } - -gb_internal bool lb_llvm_module_verification(lbGenerator *gen, bool do_threading) { - if (LLVM_IGNORE_VERIFICATION) { - return true; - } - - if (do_threading) { - for (auto const &entry : gen->modules) { - lbModule *m = entry.value; - thread_pool_add_task(lb_llvm_module_verification_worker_proc, m); - } - thread_pool_wait(); - - } else { - for (auto const &entry : gen->modules) { - lbModule *m = entry.value; - if (lb_llvm_module_verification_worker_proc(m)) { - return false; - } - } - } - - return true; -} - gb_internal void lb_add_foreign_library_paths(lbGenerator *gen) { for (auto const &entry : gen->modules) { lbModule *m = entry.value; @@ -2686,8 +2807,15 @@ gb_internal lbProcedure *lb_create_main_procedure(lbModule *m, lbProcedure *star params->Tuple.variables[1] = alloc_entity_param(nullptr, make_token_ident("fdwReason"), t_u32, false, true); params->Tuple.variables[2] = alloc_entity_param(nullptr, make_token_ident("lpReserved"), t_rawptr, false, true); call_cleanup = false; - } else if (build_context.metrics.os == TargetOs_windows && (build_context.metrics.arch == TargetArch_i386 || build_context.no_crt)) { + } else if (build_context.metrics.os == TargetOs_windows && build_context.no_crt) { name = str_lit("mainCRTStartup"); + } else if (build_context.metrics.os == TargetOs_windows && build_context.metrics.arch == TargetArch_i386 && !build_context.no_crt) { + // Windows i386 with CRT: libcmt expects _main (main with underscore prefix) + name = str_lit("main"); + has_args = true; + slice_init(¶ms->Tuple.variables, permanent_allocator(), 2); + params->Tuple.variables[0] = alloc_entity_param(nullptr, make_token_ident("argc"), t_i32, false, true); + params->Tuple.variables[1] = alloc_entity_param(nullptr, make_token_ident("argv"), t_ptr_cstring, false, true); } else if (is_arch_wasm()) { name = str_lit("_start"); call_cleanup = false; @@ -2775,7 +2903,18 @@ gb_internal lbProcedure *lb_create_main_procedure(lbModule *m, lbProcedure *star args[0] = lb_addr_load(p, all_tests_slice); lbValue result = lb_emit_call(p, runner, args); - lbValue exit_runner = lb_find_package_value(m, str_lit("os"), str_lit("exit")); + lbValue exit_runner = {}; + { + AstPackage *pkg = get_runtime_package(m->info); + + String name = str_lit("exit"); + Entity *e = scope_lookup_current(pkg->scope, name); + if (e == nullptr) { + compiler_error("Could not find type declaration for '%.*s.%.*s'\n", LIT(pkg->name), LIT(name)); + } + exit_runner = lb_find_value_from_entity(m, e); + } + auto exit_args = array_make<lbValue>(temporary_allocator(), 1); exit_args[0] = lb_emit_select(p, result, lb_const_int(m, t_int, 0), lb_const_int(m, t_int, 1)); lb_emit_call(p, exit_runner, exit_args, ProcInlining_none); @@ -2813,16 +2952,19 @@ gb_internal lbProcedure *lb_create_main_procedure(lbModule *m, lbProcedure *star } gb_internal void lb_generate_procedure(lbModule *m, lbProcedure *p) { - if (p->is_done) { + if (p->is_done.load(std::memory_order_relaxed)) { return; } + if (p->body != nullptr) { // Build Procedure m->curr_procedure = p; lb_begin_procedure_body(p); lb_build_stmt(p, p->body); lb_end_procedure_body(p); - p->is_done = true; + p->is_done.store(true, std::memory_order_relaxed); m->curr_procedure = nullptr; + } else if (p->generate_body != nullptr) { + p->generate_body(m, p); } // Add Flags @@ -2831,6 +2973,9 @@ gb_internal void lb_generate_procedure(lbModule *m, lbProcedure *p) { } lb_verify_function(m, p, true); + + MUTEX_GUARD(&m->generated_procedures_mutex); + array_add(&m->generated_procedures, p); } @@ -2845,8 +2990,6 @@ gb_internal bool lb_generate_code(lbGenerator *gen) { lbModule *default_module = &gen->default_module; CheckerInfo *info = gen->info; - auto *min_dep_set = &info->minimum_dependency_set; - switch (build_context.metrics.arch) { case TargetArch_amd64: case TargetArch_i386: @@ -2917,8 +3060,14 @@ gb_internal bool lb_generate_code(lbGenerator *gen) { LLVMCodeModel code_mode = LLVMCodeModelDefault; if (is_arch_wasm()) { code_mode = LLVMCodeModelJITDefault; + debugf("LLVM code mode: LLVMCodeModelJITDefault\n"); } else if (is_arch_x86() && build_context.metrics.os == TargetOs_freestanding) { code_mode = LLVMCodeModelKernel; + debugf("LLVM code mode: LLVMCodeModelKernel\n"); + } + + if (code_mode == LLVMCodeModelDefault) { + debugf("LLVM code mode: LLVMCodeModelDefault\n"); } String llvm_cpu = get_final_microarchitecture(); @@ -2934,7 +3083,10 @@ gb_internal bool lb_generate_code(lbGenerator *gen) { } first = false; - llvm_features = gb_string_appendc(llvm_features, "+"); + if (*str.text != '+' && *str.text != '-') { + llvm_features = gb_string_appendc(llvm_features, "+"); + } + llvm_features = gb_string_append_length(llvm_features, str.text, str.len); } @@ -3162,6 +3314,7 @@ gb_internal bool lb_generate_code(lbGenerator *gen) { String link_name = e->Procedure.link_name; if (e->pkg->kind == Package_Runtime) { if (link_name == "main" || + link_name == "_main" || link_name == "DllMain" || link_name == "WinMain" || link_name == "wWinMain" || @@ -3184,7 +3337,7 @@ gb_internal bool lb_generate_code(lbGenerator *gen) { continue; } - if (!ptr_set_exists(min_dep_set, e)) { + if (e->min_dep_count.load(std::memory_order_relaxed) == 0) { continue; } @@ -3194,47 +3347,32 @@ gb_internal bool lb_generate_code(lbGenerator *gen) { } GB_ASSERT(e->kind == Entity_Variable); + bool is_foreign = e->Variable.is_foreign; bool is_export = e->Variable.is_export; + lbModule *default_module = &gen->default_module; - lbModule *m = &gen->default_module; - String name = lb_get_entity_name(m, e); - - lbValue g = {}; - g.value = LLVMAddGlobal(m->mod, lb_type(m, e->type), alloc_cstring(permanent_allocator(), name)); - g.type = alloc_type_pointer(e->type); - - lb_apply_thread_local_model(g.value, e->Variable.thread_local_model); + lbModule *m = default_module; + lbModule *e_module = lb_module_of_entity(gen, e, default_module); - if (is_foreign) { - LLVMSetLinkage(g.value, LLVMExternalLinkage); - LLVMSetDLLStorageClass(g.value, LLVMDLLImportStorageClass); - LLVMSetExternallyInitialized(g.value, true); - lb_add_foreign_library_path(m, e->Variable.foreign_library); - } else { - LLVMSetInitializer(g.value, LLVMConstNull(lb_type(m, e->type))); - } - if (is_export) { - LLVMSetLinkage(g.value, LLVMDLLExportLinkage); - LLVMSetDLLStorageClass(g.value, LLVMDLLExportStorageClass); - } else if (!is_foreign) { - LLVMSetLinkage(g.value, USE_SEPARATE_MODULES ? LLVMWeakAnyLinkage : LLVMInternalLinkage); - } - lb_set_linkage_from_entity_flags(m, g.value, e->flags); - LLVMSetAlignment(g.value, cast(u32)type_align_of(e->type)); - - if (e->Variable.link_section.len > 0) { - LLVMSetSection(g.value, alloc_cstring(permanent_allocator(), e->Variable.link_section)); + bool const split_globals_across_modules = false; + if (split_globals_across_modules) { + m = e_module; } + String name = lb_get_entity_name(m, e); + lbGlobalVariable var = {}; - var.var = g; var.decl = decl; + lbValue g = {}; + g.type = alloc_type_pointer(e->type); + g.value = LLVMAddGlobal(m->mod, lb_type(m, e->type), alloc_cstring(permanent_allocator(), name)); + if (decl->init_expr != nullptr) { TypeAndValue tav = type_and_value_of_expr(decl->init_expr); - if (!is_type_any(e->type) && !is_type_union(e->type)) { + if (!is_type_any(e->type)) { if (tav.mode != Addressing_Invalid) { if (tav.value.kind != ExactValue_Invalid) { auto cc = LB_CONST_CONTEXT_DEFAULT; @@ -3244,6 +3382,11 @@ gb_internal bool lb_generate_code(lbGenerator *gen) { ExactValue v = tav.value; lbValue init = lb_const_value(m, tav.type, v, cc); + + LLVMDeleteGlobal(g.value); + g.value = nullptr; + g.value = LLVMAddGlobal(m->mod, LLVMTypeOf(init.value), alloc_cstring(permanent_allocator(), name)); + LLVMSetInitializer(g.value, init.value); var.is_initialized = true; if (cc.is_rodata) { @@ -3262,15 +3405,32 @@ gb_internal bool lb_generate_code(lbGenerator *gen) { LLVMSetGlobalConstant(g.value, true); } - if (e->flags & EntityFlag_Require) { - lb_append_to_compiler_used(m, g.value); - } - array_add(&global_variables, var); + lb_apply_thread_local_model(g.value, e->Variable.thread_local_model); - lb_add_entity(m, e, g); - lb_add_member(m, name, g); + if (is_foreign) { + LLVMSetLinkage(g.value, LLVMExternalLinkage); + LLVMSetDLLStorageClass(g.value, LLVMDLLImportStorageClass); + LLVMSetExternallyInitialized(g.value, true); + lb_add_foreign_library_path(m, e->Variable.foreign_library); + } else if (LLVMGetInitializer(g.value) == nullptr) { + LLVMSetInitializer(g.value, LLVMConstNull(lb_type(m, e->type))); + } + if (is_export) { + LLVMSetLinkage(g.value, LLVMDLLExportLinkage); + LLVMSetDLLStorageClass(g.value, LLVMDLLExportStorageClass); + } else if (!is_foreign) { + LLVM_SET_INTERNAL_WEAK_LINKAGE(g.value); + } + lb_set_linkage_from_entity_flags(m, g.value, e->flags); + LLVMSetAlignment(g.value, cast(u32)type_align_of(e->type)); + if (e->Variable.link_section.len > 0) { + LLVMSetSection(g.value, alloc_cstring(permanent_allocator(), e->Variable.link_section)); + } + if (e->flags & EntityFlag_Require) { + lb_append_to_compiler_used(m, g.value); + } if (m->debug_builder) { String global_name = e->token.string; @@ -3300,6 +3460,27 @@ gb_internal bool lb_generate_code(lbGenerator *gen) { LLVMGlobalSetMetadata(g.value, 0, global_variable_metadata); } } + + if (default_module == m) { + g.value = LLVMConstPointerCast(g.value, lb_type(m, alloc_type_pointer(e->type))); + + var.var = g; + array_add(&global_variables, var); + } else { + lbValue local_g = {}; + local_g.type = alloc_type_pointer(e->type); + local_g.value = LLVMAddGlobal(default_module->mod, lb_type(default_module, e->type), alloc_cstring(permanent_allocator(), name)); + LLVMSetLinkage(local_g.value, LLVMExternalLinkage); + + var.var = local_g; + array_add(&global_variables, var); + + lb_add_entity(default_module, e, local_g); + lb_add_member(default_module, name, local_g); + } + + lb_add_entity(m, e, g); + lb_add_member(m, name, g); } if (build_context.ODIN_DEBUG) { @@ -3471,15 +3652,23 @@ gb_internal bool lb_generate_code(lbGenerator *gen) { } } + TIME_SECTION("LLVM Add Foreign Library Paths"); + lb_add_foreign_library_paths(gen); + TIME_SECTION("LLVM Function Pass"); lb_llvm_function_passes(gen, do_threading && !build_context.ODIN_DEBUG); - TIME_SECTION("LLVM Module Pass"); - lb_llvm_module_passes(gen, do_threading); + TIME_SECTION("LLVM Remove Unused Functions and Globals"); + lb_remove_unused_functions_and_globals(gen); - TIME_SECTION("LLVM Module Verification"); - if (!lb_llvm_module_verification(gen, do_threading)) { - return false; + TIME_SECTION("LLVM Module Pass and Verification"); + lb_llvm_module_passes_and_verification(gen, do_threading); + + TIME_SECTION("LLVM Correct Entity Linkage"); + lb_correct_entity_linkage(gen); + + if (build_context.build_diagnostics) { + lb_do_build_diagnostics(gen); } llvm_error = nullptr; @@ -3508,11 +3697,6 @@ gb_internal bool lb_generate_code(lbGenerator *gen) { } } - TIME_SECTION("LLVM Add Foreign Library Paths"); - lb_add_foreign_library_paths(gen); - - TIME_SECTION("LLVM Correct Entity Linkage"); - lb_correct_entity_linkage(gen); //////////////////////////////////////////// for (auto const &entry: gen->modules) { diff --git a/src/llvm_backend.hpp b/src/llvm_backend.hpp index cc3dcaa4a..da5d91f2e 100644 --- a/src/llvm_backend.hpp +++ b/src/llvm_backend.hpp @@ -23,22 +23,8 @@ #include <llvm-c/Transforms/Vectorize.h> #endif -#if LLVM_VERSION_MAJOR < 11 -#error "LLVM Version 11 is the minimum required" -#elif LLVM_VERSION_MAJOR == 12 && !(LLVM_VERSION_MINOR > 0 || LLVM_VERSION_PATCH > 0) -#error "If LLVM Version 12.x.y is wanted, at least LLVM 12.0.1 is required" -#endif - -#if LLVM_VERSION_MAJOR > 12 || (LLVM_VERSION_MAJOR == 12 && LLVM_VERSION_MINOR >= 0 && LLVM_VERSION_PATCH > 0) -#define ODIN_LLVM_MINIMUM_VERSION_12 1 -#else -#define ODIN_LLVM_MINIMUM_VERSION_12 0 -#endif - -#if LLVM_VERSION_MAJOR > 13 || (LLVM_VERSION_MAJOR == 13 && LLVM_VERSION_MINOR >= 0 && LLVM_VERSION_PATCH > 0) -#define ODIN_LLVM_MINIMUM_VERSION_13 1 -#else -#define ODIN_LLVM_MINIMUM_VERSION_13 0 +#if LLVM_VERSION_MAJOR < 14 +#error "LLVM Version 14 is the minimum required" #endif #if LLVM_VERSION_MAJOR > 14 || (LLVM_VERSION_MAJOR == 14 && LLVM_VERSION_MINOR >= 0 && LLVM_VERSION_PATCH > 0) @@ -147,9 +133,13 @@ struct lbModule { LLVMModuleRef mod; LLVMContextRef ctx; + Checker *checker; + struct lbGenerator *gen; LLVMTargetMachineRef target_machine; + lbModule *polymorphic_module; + CheckerInfo *info; AstPackage *pkg; // possibly associated AstFile *file; // possibly associated @@ -171,7 +161,8 @@ struct lbModule { StringMap<lbValue> members; StringMap<lbProcedure *> procedures; PtrMap<LLVMValueRef, Entity *> procedure_values; - Array<lbProcedure *> missing_procedures_to_check; + + MPSCQueue<lbProcedure *> missing_procedures_to_check; StringMap<LLVMValueRef> const_strings; String16Map<LLVMValueRef> const_string16s; @@ -180,10 +171,13 @@ struct lbModule { StringMap<lbProcedure *> gen_procs; // key is the canonicalized name - Array<lbProcedure *> procedures_to_generate; + MPSCQueue<lbProcedure *> procedures_to_generate; Array<Entity *> global_procedures_to_create; Array<Entity *> global_types_to_create; + BlockingMutex generated_procedures_mutex; + Array<lbProcedure *> generated_procedures; + lbProcedure *curr_procedure; LLVMBuilderRef const_dummy_builder; @@ -198,7 +192,7 @@ struct lbModule { StringMap<lbAddr> objc_classes; StringMap<lbAddr> objc_selectors; StringMap<lbAddr> objc_ivars; - isize objc_next_block_id; // Used to name objective-c blocks, per module + isize objc_next_block_id; // Used to name objective-c blocks. Tracked per module. PtrMap<u64/*type hash*/, lbAddr> map_cell_info_map; // address of runtime.Map_Info PtrMap<u64/*type hash*/, lbAddr> map_info_map; // address of runtime.Map_Cell_Info @@ -232,8 +226,7 @@ struct lbGenerator : LinkerData { PtrMap<LLVMContextRef, lbModule *> modules_through_ctx; lbModule default_module; - RecursiveMutex anonymous_proc_lits_mutex; - PtrMap<Ast *, lbProcedure *> anonymous_proc_lits; + lbModule *equal_module; isize used_module_count; @@ -329,6 +322,14 @@ struct lbVariadicReuseSlices { lbAddr slice_addr; }; +struct lbGlobalVariable { + lbValue var; + lbValue init; + DeclInfo *decl; + bool is_initialized; +}; + + struct lbProcedure { u32 flags; u16 state_flags; @@ -351,9 +352,9 @@ struct lbProcedure { lbFunctionType *abi_function_type; - LLVMValueRef value; - LLVMBuilderRef builder; - bool is_done; + LLVMValueRef value; + LLVMBuilderRef builder; + std::atomic<bool> is_done; lbAddr return_ptr; Array<lbDefer> defer_stmts; @@ -391,6 +392,12 @@ struct lbProcedure { PtrMap<LLVMValueRef, lbTupleFix> tuple_fix_map; Array<lbValue> asan_stack_locals; + + void (*generate_body)(lbModule *m, lbProcedure *p); + Array<lbGlobalVariable> *global_variables; + lbProcedure *objc_names; + + Type *internal_gen_type; // map_set, map_get, etc. }; @@ -410,10 +417,12 @@ gb_internal bool lb_init_generator(lbGenerator *gen, Checker *c); gb_internal String lb_mangle_name(Entity *e); gb_internal String lb_get_entity_name(lbModule *m, Entity *e); +gb_internal LLVMAttributeRef lb_create_string_attribute(LLVMContextRef ctx, String const &key, String const &value); gb_internal LLVMAttributeRef lb_create_enum_attribute(LLVMContextRef ctx, char const *name, u64 value=0); gb_internal LLVMAttributeRef lb_create_enum_attribute_with_type(LLVMContextRef ctx, char const *name, LLVMTypeRef type); gb_internal void lb_add_proc_attribute_at_index(lbProcedure *p, isize index, char const *name, u64 value); gb_internal void lb_add_proc_attribute_at_index(lbProcedure *p, isize index, char const *name); +gb_internal void lb_add_nocapture_proc_attribute_at_index(lbProcedure *p, isize index); gb_internal lbProcedure *lb_create_procedure(lbModule *module, Entity *entity, bool ignore_body=false); @@ -434,7 +443,7 @@ static lbConstContext const LB_CONST_CONTEXT_DEFAULT_NO_LOCAL = {false, false, { gb_internal lbValue lb_const_nil(lbModule *m, Type *type); gb_internal lbValue lb_const_undef(lbModule *m, Type *type); -gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lbConstContext cc = LB_CONST_CONTEXT_DEFAULT); +gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lbConstContext cc = LB_CONST_CONTEXT_DEFAULT, Type *value_type=nullptr); gb_internal lbValue lb_const_bool(lbModule *m, Type *type, bool value); gb_internal lbValue lb_const_int(lbModule *m, Type *type, u64 value); @@ -583,7 +592,7 @@ gb_internal lbValue lb_emit_logical_binary_expr(lbProcedure *p, TokenKind op, As gb_internal lbValue lb_build_cond(lbProcedure *p, Ast *cond, lbBlock *true_block, lbBlock *false_block); gb_internal LLVMValueRef llvm_const_named_struct(lbModule *m, Type *t, LLVMValueRef *values, isize value_count_); -gb_internal LLVMValueRef llvm_const_named_struct_internal(LLVMTypeRef t, LLVMValueRef *values, isize value_count_); +gb_internal LLVMValueRef llvm_const_named_struct_internal(lbModule *m, LLVMTypeRef t, LLVMValueRef *values, isize value_count_); gb_internal void lb_set_entity_from_other_modules_linkage_correctly(lbModule *other_module, Entity *e, String const &name); gb_internal lbValue lb_expr_untyped_const_to_typed(lbModule *m, Ast *expr, Type *t); diff --git a/src/llvm_backend_const.cpp b/src/llvm_backend_const.cpp index e64be49f2..22e124792 100644 --- a/src/llvm_backend_const.cpp +++ b/src/llvm_backend_const.cpp @@ -81,7 +81,7 @@ gb_internal String lb_get_const_string(lbModule *m, lbValue value) { } -gb_internal LLVMValueRef llvm_const_cast(LLVMValueRef val, LLVMTypeRef dst) { +gb_internal LLVMValueRef llvm_const_cast(lbModule *m, LLVMValueRef val, LLVMTypeRef dst, bool *failure_) { LLVMTypeRef src = LLVMTypeOf(val); if (src == dst) { return val; @@ -93,18 +93,34 @@ gb_internal LLVMValueRef llvm_const_cast(LLVMValueRef val, LLVMTypeRef dst) { GB_ASSERT_MSG(lb_sizeof(dst) == lb_sizeof(src), "%s vs %s", LLVMPrintTypeToString(dst), LLVMPrintTypeToString(src)); LLVMTypeKind kind = LLVMGetTypeKind(dst); switch (kind) { - case LLVMPointerTypeKind: + case LLVMPointerTypeKind: { return LLVMConstPointerCast(val, dst); - case LLVMStructTypeKind: - // GB_PANIC("%s -> %s", LLVMPrintValueToString(val), LLVMPrintTypeToString(dst)); - // NOTE(bill): It's not possible to do a bit cast on a struct, why was this code even here in the first place? - // It seems mostly to exist to get around the "anonymous -> named" struct assignments - // return LLVMConstBitCast(val, dst); - return val; - default: - GB_PANIC("Unhandled const cast %s to %s", LLVMPrintTypeToString(src), LLVMPrintTypeToString(dst)); + } + case LLVMStructTypeKind: { + unsigned src_n = LLVMCountStructElementTypes(src); + unsigned dst_n = LLVMCountStructElementTypes(dst); + if (src_n != dst_n) goto failure; + + LLVMValueRef *field_vals = temporary_alloc_array<LLVMValueRef>(dst_n); + for (unsigned i = 0; i < dst_n; i++) { + LLVMValueRef field_val = llvm_const_extract_value(m, val, i); + if (field_val == nullptr) goto failure; + + LLVMTypeRef dst_elem_ty = LLVMStructGetTypeAtIndex(dst, i); + field_vals[i] = llvm_const_cast(m, field_val, dst_elem_ty, failure_); + if (failure_ && *failure_) goto failure; + } + + if (!LLVMIsLiteralStruct(dst)) { + return LLVMConstNamedStruct(dst, field_vals, dst_n); + } else { + return LLVMConstStructInContext(m->ctx, field_vals, dst_n, LLVMIsPackedStruct(dst)); + } + } } +failure: + if (failure_) *failure_ = true; return val; } @@ -129,13 +145,13 @@ gb_internal LLVMValueRef llvm_const_string_internal(lbModule *m, Type *t, LLVMVa LLVMConstNull(lb_type(m, t_i32)), len, }; - return llvm_const_named_struct_internal(lb_type(m, t), values, 3); + return llvm_const_named_struct_internal(m, lb_type(m, t), values, 3); } else { LLVMValueRef values[2] = { data, len, }; - return llvm_const_named_struct_internal(lb_type(m, t), values, 2); + return llvm_const_named_struct_internal(m, lb_type(m, t), values, 2); } } @@ -147,13 +163,13 @@ gb_internal LLVMValueRef llvm_const_string16_internal(lbModule *m, Type *t, LLVM LLVMConstNull(lb_type(m, t_i32)), len, }; - return llvm_const_named_struct_internal(lb_type(m, t), values, 3); + return llvm_const_named_struct_internal(m, lb_type(m, t), values, 3); } else { LLVMValueRef values[2] = { data, len, }; - return llvm_const_named_struct_internal(lb_type(m, t), values, 2); + return llvm_const_named_struct_internal(m, lb_type(m, t), values, 2); } } @@ -165,12 +181,11 @@ gb_internal LLVMValueRef llvm_const_named_struct(lbModule *m, Type *t, LLVMValue unsigned value_count = cast(unsigned)value_count_; unsigned elem_count = LLVMCountStructElementTypes(struct_type); if (elem_count == value_count) { - return llvm_const_named_struct_internal(struct_type, values, value_count_); + return llvm_const_named_struct_internal(m, struct_type, values, value_count_); } Type *bt = base_type(t); - GB_ASSERT(bt->kind == Type_Struct); - - GB_ASSERT(value_count_ == bt->Struct.fields.count); + GB_ASSERT(bt->kind == Type_Struct || bt->kind == Type_Union); + GB_ASSERT(bt->kind != Type_Struct || value_count_ == bt->Struct.fields.count); auto field_remapping = lb_get_struct_remapping(m, t); unsigned values_with_padding_count = elem_count; @@ -185,25 +200,40 @@ gb_internal LLVMValueRef llvm_const_named_struct(lbModule *m, Type *t, LLVMValue } } - return llvm_const_named_struct_internal(struct_type, values_with_padding, values_with_padding_count); + return llvm_const_named_struct_internal(m, struct_type, values_with_padding, values_with_padding_count); } -gb_internal LLVMValueRef llvm_const_named_struct_internal(LLVMTypeRef t, LLVMValueRef *values, isize value_count_) { +gb_internal LLVMValueRef llvm_const_named_struct_internal(lbModule *m, LLVMTypeRef t, LLVMValueRef *values, isize value_count_) { unsigned value_count = cast(unsigned)value_count_; unsigned elem_count = LLVMCountStructElementTypes(t); GB_ASSERT_MSG(value_count == elem_count, "%s %u %u", LLVMPrintTypeToString(t), value_count, elem_count); + bool failure = false; for (unsigned i = 0; i < elem_count; i++) { LLVMTypeRef elem_type = LLVMStructGetTypeAtIndex(t, i); - values[i] = llvm_const_cast(values[i], elem_type); + values[i] = llvm_const_cast(m, values[i], elem_type, &failure); + } + + if (failure) { + return LLVMConstStructInContext(m->ctx, values, value_count, true); } return LLVMConstNamedStruct(t, values, value_count); } -gb_internal LLVMValueRef llvm_const_array(LLVMTypeRef elem_type, LLVMValueRef *values, isize value_count_) { +gb_internal LLVMValueRef llvm_const_array(lbModule *m, LLVMTypeRef elem_type, LLVMValueRef *values, isize value_count_) { unsigned value_count = cast(unsigned)value_count_; + bool failure = false; + for (unsigned i = 0; i < value_count; i++) { + values[i] = llvm_const_cast(m, values[i], elem_type, &failure); + } + if (failure) { + return LLVMConstStructInContext(m->ctx, values, value_count, false); + } for (unsigned i = 0; i < value_count; i++) { - values[i] = llvm_const_cast(values[i], elem_type); + if (elem_type != LLVMTypeOf(values[i])) { + return LLVMConstStructInContext(m->ctx, values, value_count, false); + } } + return LLVMConstArray(elem_type, values, value_count); } @@ -461,7 +491,7 @@ gb_internal LLVMValueRef lb_build_constant_array_values(lbModule *m, Type *type, return lb_addr_load(p, v).value; } - return llvm_const_array(lb_type(m, elem_type), values, cast(unsigned int)count); + return llvm_const_array(m, lb_type(m, elem_type), values, cast(unsigned int)count); } gb_internal LLVMValueRef lb_big_int_to_llvm(lbModule *m, Type *original_type, BigInt const *a) { @@ -482,7 +512,7 @@ gb_internal LLVMValueRef lb_big_int_to_llvm(lbModule *m, Type *original_type, Bi max_count = mp_pack_count(a, nails, size); if (sz < max_count) { debug_print_big_int(a); - gb_printf_err("%s -> %tu\n", type_to_string(original_type), sz);; + gb_printf_err("%s -> %tu\n", type_to_string(original_type), sz); } GB_ASSERT_MSG(sz >= max_count, "max_count: %tu, sz: %tu, written: %tu, type %s", max_count, sz, written, type_to_string(original_type)); GB_ASSERT(gb_size_of(rop64) >= sz); @@ -531,13 +561,111 @@ gb_internal bool lb_is_nested_possibly_constant(Type *ft, Selection const &sel, } - if (is_type_raw_union(ft) || is_type_typeid(ft)) { + if (is_type_raw_union(ft)) { return false; } return lb_is_elem_const(elem, ft); } -gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lbConstContext cc) { +#if LLVM_VERSION_MAJOR == 14 +LLVMValueRef llvm_const_pad_to_size(lbModule *m, LLVMValueRef val, LLVMTypeRef dst_ty) { + LLVMContextRef ctx = m->ctx; + LLVMTargetDataRef td = LLVMGetModuleDataLayout(m->mod); + LLVMTypeRef src_ty = LLVMTypeOf(val); + unsigned src_bits = (unsigned)LLVMSizeOfTypeInBits(td, src_ty); + unsigned dst_bits = (unsigned)LLVMSizeOfTypeInBits(td, dst_ty); + + LLVMValueRef as_int = nullptr; + LLVMTypeKind src_kind = LLVMGetTypeKind(src_ty); + + if (src_kind == LLVMIntegerTypeKind || + src_kind == LLVMFloatTypeKind || + src_kind == LLVMDoubleTypeKind || + src_kind == LLVMPointerTypeKind || + src_kind == LLVMVectorTypeKind) { + LLVMTypeRef src_int_ty = LLVMIntTypeInContext(ctx, src_bits); + as_int = LLVMConstBitCast(val, src_int_ty); + + } else if (src_kind == LLVMArrayTypeKind) { + unsigned elem_count = LLVMGetArrayLength(src_ty); + LLVMTypeRef elem_ty = LLVMGetElementType(src_ty); + unsigned elem_bits = (unsigned)LLVMSizeOfTypeInBits(td, elem_ty); + LLVMTypeRef src_int_ty = LLVMIntTypeInContext(ctx, src_bits); + as_int = LLVMConstInt(src_int_ty, 0, false); + + for (unsigned i = 0; i < elem_count; i++) { + LLVMValueRef elem = llvm_const_extract_value(m, val, i); + LLVMTypeRef elem_int_ty = LLVMIntTypeInContext(ctx, elem_bits); + LLVMValueRef elem_int = llvm_const_pad_to_size(m, elem, elem_int_ty); + LLVMValueRef shifted = LLVMConstShl(LLVMConstZExt(elem_int, src_int_ty), LLVMConstInt(src_int_ty, i * elem_bits, false)); + as_int = LLVMConstOr(as_int, shifted); + } + } else if (src_kind == LLVMStructTypeKind) { + unsigned field_count = LLVMCountStructElementTypes(src_ty); + LLVMTypeRef src_int_ty = LLVMIntTypeInContext(ctx, src_bits); + as_int = LLVMConstInt(src_int_ty, 0, false); + + for (unsigned i = 0; i < field_count; i++) { + LLVMTypeRef field_ty = LLVMStructGetTypeAtIndex(src_ty, i); + unsigned field_bits = (unsigned)LLVMSizeOfTypeInBits(td, field_ty); + LLVMValueRef field = llvm_const_extract_value(m, val, i); + + LLVMTypeRef field_int_ty = LLVMIntTypeInContext(ctx, field_bits); + LLVMValueRef field_int = llvm_const_pad_to_size(m, field, field_int_ty); + + uint64_t field_offset_bytes = LLVMOffsetOfElement(td, src_ty, i); + uint64_t field_offset_bits = field_offset_bytes * 8; + + LLVMValueRef shifted = LLVMConstShl(LLVMConstZExt(field_int, src_int_ty), LLVMConstInt(src_int_ty, field_offset_bits, false)); + as_int = LLVMConstOr(as_int, shifted); + } + } else { + gb_printf_err("unsupported const_pad source type: %s\n", LLVMPrintTypeToString(src_ty)); + return nullptr; + } + + if (src_bits != dst_bits) { + LLVMTypeRef dst_int_ty = LLVMIntTypeInContext(ctx, dst_bits); + if (src_bits < dst_bits) { + as_int = LLVMConstZExt(as_int, dst_int_ty); + } else { + as_int = LLVMConstTrunc(as_int, dst_int_ty); + } + } + + LLVMTypeKind dst_kind = LLVMGetTypeKind(dst_ty); + + if (dst_kind == LLVMIntegerTypeKind || + dst_kind == LLVMFloatTypeKind || + dst_kind == LLVMDoubleTypeKind || + dst_kind == LLVMPointerTypeKind || + dst_kind == LLVMVectorTypeKind) { + return LLVMConstBitCast(as_int, dst_ty); + + } else if (dst_kind == LLVMArrayTypeKind) { + unsigned elem_count = LLVMGetArrayLength(dst_ty); + LLVMTypeRef elem_ty = LLVMGetElementType(dst_ty); + unsigned elem_bits = (unsigned)LLVMSizeOfTypeInBits(td, elem_ty); + + LLVMValueRef *elems = temporary_alloc_array<LLVMValueRef>(elem_count); + LLVMTypeRef as_int_ty = LLVMTypeOf(as_int); + + for (unsigned i = 0; i < elem_count; i++) { + LLVMValueRef shifted = LLVMConstLShr(as_int, LLVMConstInt(as_int_ty, i * elem_bits, false)); + LLVMTypeRef elem_int_ty = LLVMIntTypeInContext(ctx, elem_bits); + LLVMValueRef trunc = LLVMConstTrunc(shifted, elem_int_ty); + elems[i] = llvm_const_pad_to_size(m, trunc, elem_ty); + } + + return LLVMConstArray(elem_ty, elems, elem_count); + } + + gb_printf_err("unsupported const_pad destination type: %s\n", LLVMPrintTypeToString(dst_ty)); + return nullptr; +} +#endif + +gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lbConstContext cc, Type *value_type) { if (cc.allow_local) { cc.is_rodata = false; } @@ -552,23 +680,143 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb type = core_type(type); value = convert_exact_value_for_type(value, type); - if (value.kind == ExactValue_Typeid) { - return lb_typeid(m, value.value_typeid); - } + bool is_local = cc.allow_local && m->curr_procedure != nullptr; - if (value.kind == ExactValue_Invalid) { - return lb_const_nil(m, original_type); + if (is_type_union(type) && is_type_union_constantable(type)) { + Type *bt = base_type(type); + GB_ASSERT(bt->kind == Type_Union); + if (bt->Union.variants.count == 0) { + return lb_const_nil(m, original_type); + } else if (bt->Union.variants.count == 1) { + if (value.kind == ExactValue_Compound) { + ast_node(cl, CompoundLit, value.value_compound); + if (cl->elems.count == 0) { + if (cl->type == nullptr) { + return lb_const_nil(m, original_type); + } + if (are_types_identical(type_of_expr(cl->type), original_type)) { + return lb_const_nil(m, original_type); + } + } + } + + if (value_type == t_untyped_nil) { + return lb_const_nil(m, original_type); + } + + Type *t = bt->Union.variants[0]; + lbValue cv = lb_const_value(m, t, value, cc); + GB_ASSERT(LLVMIsConstant(cv.value)); + + LLVMTypeRef llvm_type = lb_type(m, original_type); + + if (is_type_union_maybe_pointer(type)) { + LLVMValueRef values[1] = {cv.value}; + res.value = llvm_const_named_struct_internal(m, llvm_type, values, 1); + res.type = original_type; + return res; + } else { + + unsigned tag_value = 1; + if (bt->Union.kind == UnionType_no_nil) { + tag_value = 0; + } + LLVMValueRef tag = LLVMConstInt(LLVMStructGetTypeAtIndex(llvm_type, 1), tag_value, false); + LLVMValueRef padding = nullptr; + LLVMValueRef values[3] = {cv.value, tag, padding}; + + isize value_count = 2; + if (LLVMCountStructElementTypes(llvm_type) > 2) { + value_count = 3; + padding = LLVMConstNull(LLVMStructGetTypeAtIndex(llvm_type, 2)); + } + res.value = llvm_const_named_struct_internal(m, llvm_type, values, value_count); + res.type = original_type; + return res; + } + } else { + if (value_type == nullptr) { + if (value.kind == ExactValue_Compound) { + ast_node(cl, CompoundLit, value.value_compound); + if (cl->elems.count == 0) { + return lb_const_nil(m, original_type); + } + } else if (value.kind == ExactValue_Invalid) { + return lb_const_nil(m, original_type); + } + } else if (value_type == t_untyped_nil) { + return lb_const_nil(m, original_type); + } + + GB_ASSERT_MSG(value_type != nullptr, "%s :: %s", type_to_string(original_type), exact_value_to_string(value)); + + i64 block_size = bt->Union.variant_block_size; + + if (are_types_identical(value_type, original_type)) { + if (value.kind == ExactValue_Compound) { + ast_node(cl, CompoundLit, value.value_compound); + if (cl->elems.count == 0) { + return lb_const_nil(m, original_type); + } + } else if (value.kind == ExactValue_Invalid) { + return lb_const_nil(m, original_type); + } + + GB_PANIC("%s vs %s", type_to_string(value_type), type_to_string(original_type)); + } + + lbValue cv = lb_const_value(m, value_type, value, cc, value_type); + Type *variant_type = cv.type; + + LLVMValueRef values[4] = {}; + unsigned value_count = 0; + + #if LLVM_VERSION_MAJOR == 14 + LLVMTypeRef block_type = lb_type_internal_union_block_type(m, bt); + values[value_count++] = llvm_const_pad_to_size(m, cv.value, block_type); + #else + values[value_count++] = cv.value; + if (type_size_of(variant_type) != block_size) { + LLVMTypeRef padding_type = lb_type_padding_filler(m, block_size - type_size_of(variant_type), 1); + values[value_count++] = LLVMConstNull(padding_type); + } + #endif + + Type *tag_type = union_tag_type(bt); + LLVMTypeRef llvm_tag_type = lb_type(m, tag_type); + i64 tag_index = union_variant_index(bt, variant_type); + GB_ASSERT(tag_index >= 0); + values[value_count++] = LLVMConstInt(llvm_tag_type, tag_index, false); + i64 used_size = block_size + type_size_of(tag_type); + i64 union_size = type_size_of(bt); + i64 padding = union_size - used_size; + if (padding > 0) { + LLVMTypeRef padding_type = lb_type_padding_filler(m, padding, 1); + values[value_count++] = LLVMConstNull(padding_type); + } + + res.value = LLVMConstStructInContext(m->ctx, values, value_count, true); + return res; + } } if (value.kind == ExactValue_Procedure) { lbValue res = {}; - Ast *expr = unparen_expr(value.value_procedure); - GB_ASSERT(expr != nullptr); - if (expr->kind == Ast_ProcLit) { - res = lb_generate_anonymous_proc_lit(m, str_lit("_proclit"), expr); - } else { + for (;;) { + Ast *expr = unparen_expr(value.value_procedure); + GB_ASSERT(expr != nullptr); + if (expr->kind == Ast_ProcLit) { + res = lb_generate_anonymous_proc_lit(m, str_lit("_proclit"), expr); + break; + } Entity *e = entity_from_expr(expr); - res = lb_find_procedure_value_from_entity(m, e); + GB_ASSERT(e != nullptr); + if (e->kind != Entity_Constant) { + res = lb_find_procedure_value_from_entity(m, e); + break; + } + value = e->Constant.value; + GB_ASSERT(value.kind == ExactValue_Procedure); } if (res.value == nullptr) { // This is an unspecialized polymorphic procedure, return nil or dummy value @@ -583,7 +831,23 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb return res; } - bool is_local = cc.allow_local && m->curr_procedure != nullptr; + // NOTE(bill): This has to be done AFTER the union stuff + if (value.kind == ExactValue_Invalid) { + return lb_const_nil(m, original_type); + } + + + if (value.kind == ExactValue_Typeid) { + return lb_typeid(m, value.value_typeid); + } + + if (value.kind == ExactValue_Compound) { + ast_node(cl, CompoundLit, value.value_compound); + if (cl->elems.count == 0) { + return lb_const_nil(m, original_type); + } + } + // GB_ASSERT_MSG(is_type_typed(type), "%s", type_to_string(type)); @@ -596,7 +860,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb GB_ASSERT(is_type_slice(type)); res.value = lb_find_or_add_entity_string16_slice_with_type(m, value.value_string16, original_type).value; return res; - }else { + } else { ast_node(cl, CompoundLit, value.value_compound); isize count = cl->elems.count; @@ -606,19 +870,39 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb count = gb_max(cast(isize)cl->max_count, count); Type *elem = base_type(type)->Slice.elem; Type *t = alloc_type_array(elem, count); - lbValue backing_array = lb_const_value(m, t, value, cc); + lbValue backing_array = lb_const_value(m, t, value, cc, nullptr); LLVMValueRef array_data = nullptr; + if (is_local) { // NOTE(bill, 2020-06-08): This is a bit of a hack but a "constant" slice needs // its backing data on the stack lbProcedure *p = m->curr_procedure; LLVMTypeRef llvm_type = lb_type(m, t); - array_data = llvm_alloca(p, llvm_type, 16); + unsigned alignment = cast(unsigned)gb_max(type_align_of(t), 16); + + + bool do_local_copy = false; + if (do_local_copy) { + array_data = llvm_alloca(p, llvm_type, alignment); + + LLVMValueRef local_copy = llvm_alloca(p, LLVMTypeOf(backing_array.value), alignment); + LLVMBuildStore(p->builder, backing_array.value, local_copy); + + LLVMBuildMemCpy(p->builder, + array_data, alignment, + local_copy, alignment, + LLVMConstInt(lb_type(m, t_int), type_size_of(t), false) + ); + } else { + array_data = llvm_alloca(p, LLVMTypeOf(backing_array.value), alignment); + LLVMBuildStore(p->builder, backing_array.value, array_data); + + array_data = LLVMBuildPointerCast(p->builder, array_data, LLVMPointerType(llvm_type, 0), ""); + } - LLVMBuildStore(p->builder, backing_array.value, array_data); { LLVMValueRef indices[2] = {llvm_zero(m), llvm_zero(m)}; @@ -640,7 +924,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb String name = make_string(cast(u8 const *)str, gb_string_length(str)); Entity *e = alloc_entity_constant(nullptr, make_token_ident(name), t, value); - array_data = LLVMAddGlobal(m->mod, lb_type(m, t), str); + array_data = LLVMAddGlobal(m->mod, LLVMTypeOf(backing_array.value), str); LLVMSetInitializer(array_data, backing_array.value); if (cc.link_section.len > 0) { @@ -651,15 +935,14 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb } lbValue g = {}; - g.value = array_data; + g.value = LLVMConstPointerCast(array_data, LLVMPointerType(lb_type(m, t), 0)); g.type = t; lb_add_entity(m, e, g); lb_add_member(m, name, g); { - LLVMValueRef indices[2] = {llvm_zero(m), llvm_zero(m)}; - LLVMValueRef ptr = LLVMConstInBoundsGEP2(lb_type(m, t), array_data, indices, 2); + LLVMValueRef ptr = g.value; LLVMValueRef len = LLVMConstInt(lb_type(m, t_int), count, true); LLVMValueRef values[2] = {ptr, len}; @@ -692,7 +975,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb } GB_ASSERT(offset == s.len); - res.value = llvm_const_array(et, elems, cast(unsigned)count); + res.value = llvm_const_array(m, et, elems, cast(unsigned)count); return res; } // NOTE(bill, 2021-10-07): Allow for array programming value constants @@ -722,7 +1005,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb elems[i] = single_elem.value; } - res.value = llvm_const_array(lb_type(m, elem), elems, cast(unsigned)count); + res.value = llvm_const_array(m, lb_type(m, elem), elems, cast(unsigned)count); return res; } else if (is_type_matrix(type) && value.kind != ExactValue_Invalid && @@ -734,7 +1017,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb Type *elem = type->Matrix.elem; lbValue single_elem = lb_const_value(m, elem, value, cc); - single_elem.value = llvm_const_cast(single_elem.value, lb_type(m, elem)); + single_elem.value = llvm_const_cast(m, single_elem.value, lb_type(m, elem), /*failure_*/nullptr); i64 total_elem_count = matrix_type_total_internal_elems(type); LLVMValueRef *elems = gb_alloc_array(permanent_allocator(), LLVMValueRef, cast(isize)total_elem_count); @@ -756,7 +1039,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb Type *elem = type->SimdVector.elem; lbValue single_elem = lb_const_value(m, elem, value, cc); - single_elem.value = llvm_const_cast(single_elem.value, lb_type(m, elem)); + single_elem.value = llvm_const_cast(m, single_elem.value, lb_type(m, elem), /*failure_*/nullptr); LLVMValueRef *elems = gb_alloc_array(permanent_allocator(), LLVMValueRef, count); for (i64 i = 0; i < count; i++) { @@ -981,7 +1264,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb } if (lo == i) { TypeAndValue tav = fv->value->tav; - LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc).value; + LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc, tav.type).value; for (i64 k = lo; k < hi; k++) { aos_values[value_index++] = val; } @@ -996,7 +1279,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb i64 index = exact_value_to_i64(index_tav.value); if (index == i) { TypeAndValue tav = fv->value->tav; - LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc).value; + LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc, tav.type).value; aos_values[value_index++] = val; found = true; break; @@ -1049,7 +1332,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb for (isize i = 0; i < elem_count; i++) { TypeAndValue tav = cl->elems[i]->tav; GB_ASSERT(tav.mode != Addressing_Invalid); - aos_values[i] = lb_const_value(m, elem_type, tav.value, cc).value; + aos_values[i] = lb_const_value(m, elem_type, tav.value, cc, tav.type).value; } for (isize i = elem_count; i < type->Struct.soa_count; i++) { aos_values[i] = nullptr; @@ -1116,7 +1399,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb } if (lo == i) { TypeAndValue tav = fv->value->tav; - LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc).value; + LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc, tav.type).value; for (i64 k = lo; k < hi; k++) { values[value_index++] = val; } @@ -1131,7 +1414,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb i64 index = exact_value_to_i64(index_tav.value); if (index == i) { TypeAndValue tav = fv->value->tav; - LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc).value; + LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc, tav.type).value; values[value_index++] = val; found = true; break; @@ -1146,12 +1429,12 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb res.value = lb_build_constant_array_values(m, type, elem_type, cast(isize)type->Array.count, values, cc); return res; - } else if (value.value_compound->tav.type == elem_type) { + } else if (are_types_identical(value.value_compound->tav.type, elem_type)) { // Compound is of array item type; expand its value to all items in array. LLVMValueRef* values = gb_alloc_array(temporary_allocator(), LLVMValueRef, cast(isize)type->Array.count); for (isize i = 0; i < type->Array.count; i++) { - values[i] = lb_const_value(m, elem_type, value, cc).value; + values[i] = lb_const_value(m, elem_type, value, cc, elem_type).value; } res.value = lb_build_constant_array_values(m, type, elem_type, cast(isize)type->Array.count, values, cc); @@ -1165,7 +1448,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb for (isize i = 0; i < elem_count; i++) { TypeAndValue tav = cl->elems[i]->tav; GB_ASSERT(tav.mode != Addressing_Invalid); - values[i] = lb_const_value(m, elem_type, tav.value, cc).value; + values[i] = lb_const_value(m, elem_type, tav.value, cc, tav.type).value; } for (isize i = elem_count; i < type->Array.count; i++) { values[i] = LLVMConstNull(lb_type(m, elem_type)); @@ -1211,7 +1494,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb } if (lo == i) { TypeAndValue tav = fv->value->tav; - LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc).value; + LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc, tav.type).value; for (i64 k = lo; k < hi; k++) { values[value_index++] = val; } @@ -1226,7 +1509,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb i64 index = exact_value_to_i64(index_tav.value); if (index == i) { TypeAndValue tav = fv->value->tav; - LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc).value; + LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc, tav.type).value; values[value_index++] = val; found = true; break; @@ -1249,7 +1532,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb for (isize i = 0; i < elem_count; i++) { TypeAndValue tav = cl->elems[i]->tav; GB_ASSERT(tav.mode != Addressing_Invalid); - values[i] = lb_const_value(m, elem_type, tav.value, cc).value; + values[i] = lb_const_value(m, elem_type, tav.value, cc, tav.type).value; } for (isize i = elem_count; i < type->EnumeratedArray.count; i++) { values[i] = LLVMConstNull(lb_type(m, elem_type)); @@ -1294,7 +1577,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb } if (lo == i) { TypeAndValue tav = fv->value->tav; - LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc).value; + LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc, tav.type).value; for (i64 k = lo; k < hi; k++) { values[value_index++] = val; } @@ -1309,7 +1592,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb i64 index = exact_value_to_i64(index_tav.value); if (index == i) { TypeAndValue tav = fv->value->tav; - LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc).value; + LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc, tav.type).value; values[value_index++] = val; found = true; break; @@ -1328,7 +1611,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb for (isize i = 0; i < elem_count; i++) { TypeAndValue tav = cl->elems[i]->tav; GB_ASSERT(tav.mode != Addressing_Invalid); - values[i] = lb_const_value(m, elem_type, tav.value, cc).value; + values[i] = lb_const_value(m, elem_type, tav.value, cc, tav.type).value; } LLVMTypeRef et = lb_type(m, elem_type); @@ -1336,7 +1619,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb values[i] = LLVMConstNull(et); } for (isize i = 0; i < total_elem_count; i++) { - values[i] = llvm_const_cast(values[i], et); + values[i] = llvm_const_cast(m, values[i], et, /*failure_*/nullptr); } res.value = LLVMConstVector(values, cast(unsigned)total_elem_count); @@ -1350,6 +1633,39 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb } if (is_type_raw_union(type)) { + if (is_type_raw_union_constantable(type)) { + GB_ASSERT(cl->elems.count == 1); + GB_ASSERT(cl->elems[0]->kind == Ast_FieldValue); + ast_node(fv, FieldValue, cl->elems[0]); + Entity *f = entity_of_node(fv->field); + + TypeAndValue tav = fv->value->tav; + if (tav.value.kind != ExactValue_Invalid) { + lbValue value = lb_const_value(m, f->type, tav.value, cc, f->type); + + LLVMValueRef values[2]; + unsigned value_count = 0; + + values[value_count++] = value.value; + + i64 union_alignment = type_align_of(type); + i64 value_alignment = type_align_of(f->type); + i64 alignment = gb_max(gb_min(value_alignment, union_alignment), 1); + + i64 union_size = type_size_of(type); + i64 value_size = lb_sizeof(LLVMTypeOf(value.value)); + i64 padding = union_size-value_size; + if (padding > 0) { + LLVMTypeRef padding_type = lb_type_padding_filler(m, padding, alignment); + values[value_count++] = LLVMConstNull(padding_type); + } + + LLVMValueRef res = LLVMConstStructInContext(m->ctx, values, value_count, /*packed*/padding > 0); + + return {res, original_type}; + } + + } return lb_const_nil(m, original_type); } @@ -1377,7 +1693,10 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb i32 index = field_remapping[f->Variable.field_index]; if (elem_type_can_be_constant(f->type)) { if (sel.index.count == 1) { - values[index] = lb_const_value(m, f->type, tav.value, cc).value; + lbValue value = lb_const_value(m, f->type, tav.value, cc, tav.type); + LLVMTypeRef value_type = LLVMTypeOf(value.value); + GB_ASSERT_MSG(lb_sizeof(value_type) == type_size_of(f->type), "%s vs %s", LLVMPrintTypeToString(value_type), type_to_string(f->type)); + values[index] = value.value; visited[index] = true; } else { if (!visited[index]) { @@ -1423,7 +1742,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb } } if (is_constant) { - LLVMValueRef elem_value = lb_const_value(m, tav.type, tav.value, cc).value; + LLVMValueRef elem_value = lb_const_value(m, tav.type, tav.value, cc, tav.type).value; if (LLVMIsConstant(elem_value) && LLVMIsConstant(values[index])) { values[index] = llvm_const_insert_value(m, values[index], elem_value, idx_list, idx_list_len); } else if (is_local) { @@ -1477,7 +1796,10 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb i32 index = field_remapping[f->Variable.field_index]; if (elem_type_can_be_constant(f->type)) { - values[index] = lb_const_value(m, f->type, val, cc).value; + lbValue value = lb_const_value(m, f->type, tav.value, cc, tav.type); + LLVMTypeRef value_type = LLVMTypeOf(value.value); + GB_ASSERT_MSG(lb_sizeof(value_type) == type_size_of(f->type), "%s vs %s", LLVMPrintTypeToString(value_type), type_to_string(f->type)); + values[index] = value.value; visited[index] = true; } } @@ -1503,7 +1825,9 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb } if (is_constant) { - res.value = llvm_const_named_struct_internal(struct_type, values, cast(unsigned)value_count); + res.value = llvm_const_named_struct_internal(m, struct_type, values, cast(unsigned)value_count); + LLVMTypeRef res_type = LLVMTypeOf(res.value); + GB_ASSERT(lb_sizeof(res_type) == lb_sizeof(struct_type)); return res; } else { // TODO(bill): THIS IS HACK BUT IT WORKS FOR WHAT I NEED @@ -1517,7 +1841,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb new_values[i] = LLVMConstNull(LLVMTypeOf(old_value)); } } - LLVMValueRef constant_value = llvm_const_named_struct_internal(struct_type, new_values, cast(unsigned)value_count); + LLVMValueRef constant_value = llvm_const_named_struct_internal(m, struct_type, new_values, cast(unsigned)value_count); GB_ASSERT(is_local); lbProcedure *p = m->curr_procedure; @@ -1611,7 +1935,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb TypeAndValue tav = fv->value->tav; - LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc).value; + LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc, tav.type).value; for (i64 k = lo; k < hi; k++) { i64 offset = matrix_row_major_index_to_offset(type, k); GB_ASSERT(values[offset] == nullptr); @@ -1623,7 +1947,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb i64 index = exact_value_to_i64(index_tav.value); GB_ASSERT(index < max_count); TypeAndValue tav = fv->value->tav; - LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc).value; + LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc, tav.type).value; i64 offset = matrix_row_major_index_to_offset(type, index); GB_ASSERT(values[offset] == nullptr); values[offset] = val; @@ -1647,7 +1971,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb GB_ASSERT(tav.mode != Addressing_Invalid); i64 offset = 0; offset = matrix_row_major_index_to_offset(type, i); - values[offset] = lb_const_value(m, elem_type, tav.value, cc).value; + values[offset] = lb_const_value(m, elem_type, tav.value, cc, tav.type).value; } for (isize i = 0; i < total_count; i++) { if (values[i] == nullptr) { diff --git a/src/llvm_backend_debug.cpp b/src/llvm_backend_debug.cpp index 182920fc7..187aebf7c 100644 --- a/src/llvm_backend_debug.cpp +++ b/src/llvm_backend_debug.cpp @@ -704,7 +704,7 @@ gb_internal LLVMMetadataRef lb_debug_type_internal(lbModule *m, Type *type) { case Basic_uintptr: return lb_debug_type_basic_type(m, str_lit("uintptr"), ptr_bits, LLVMDWARFTypeEncoding_Unsigned); case Basic_typeid: - return lb_debug_type_basic_type(m, str_lit("typeid"), ptr_bits, LLVMDWARFTypeEncoding_Unsigned); + return lb_debug_type_basic_type(m, str_lit("typeid"), 64, LLVMDWARFTypeEncoding_Unsigned); // Endian Specific Types case Basic_i16le: return lb_debug_type_basic_type(m, str_lit("i16le"), 16, LLVMDWARFTypeEncoding_Signed, LLVMDIFlagLittleEndian); @@ -820,8 +820,8 @@ gb_internal LLVMMetadataRef lb_debug_type_internal(lbModule *m, Type *type) { { LLVMMetadataRef elements[2] = {}; elements[0] = lb_debug_struct_field(m, str_lit("data"), t_rawptr, 0); - elements[1] = lb_debug_struct_field(m, str_lit("id"), t_typeid, ptr_bits); - return lb_debug_basic_struct(m, str_lit("any"), 2*ptr_bits, ptr_bits, elements, gb_count_of(elements)); + elements[1] = lb_debug_struct_field(m, str_lit("id"), t_typeid, 64); + return lb_debug_basic_struct(m, str_lit("any"), 128, 64, elements, gb_count_of(elements)); } // Untyped types @@ -1327,7 +1327,7 @@ gb_internal void lb_add_debug_info_for_global_constant_from_entity(lbGenerator * } lbModule *m = &gen->default_module; if (USE_SEPARATE_MODULES) { - m = lb_module_of_entity(gen, e); + m = lb_module_of_entity(gen, e, m); } GB_ASSERT(m != nullptr); diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index ebc3ec158..dba61df44 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -634,7 +634,7 @@ gb_internal LLVMValueRef lb_matrix_to_trimmed_vector(lbProcedure *p, lbValue m) } -gb_internal lbValue lb_emit_matrix_tranpose(lbProcedure *p, lbValue m, Type *type) { +gb_internal lbValue lb_emit_matrix_transpose(lbProcedure *p, lbValue m, Type *type) { if (is_type_array(m.type)) { i32 rank = type_math_rank(m.type); if (rank == 2) { @@ -664,7 +664,12 @@ gb_internal lbValue lb_emit_matrix_tranpose(lbProcedure *p, lbValue m, Type *typ Type *mt = base_type(m.type); GB_ASSERT(mt->kind == Type_Matrix); - if (lb_is_matrix_simdable(mt)) { + Type *rt = base_type(type); + if (rt->kind == Type_Matrix && rt->Matrix.is_row_major != mt->Matrix.is_row_major) { + GB_PANIC("TODO: transpose with changing layout"); + } + + if (lb_is_matrix_simdable(mt) && lb_is_matrix_simdable(type)) { unsigned stride = cast(unsigned)matrix_type_stride_in_elems(mt); unsigned row_count = cast(unsigned)mt->Matrix.row_count; unsigned column_count = cast(unsigned)mt->Matrix.column_count; @@ -1156,8 +1161,7 @@ gb_internal LLVMValueRef lb_integer_division(lbProcedure *p, LLVMValueRef lhs, L case IntegerDivisionByZero_Zero: return zero; case IntegerDivisionByZero_AllBits: - // return all_bits; - break; + return all_bits; } } else { if (!is_signed && lb_sizeof(type) <= 8) { @@ -1193,7 +1197,6 @@ gb_internal LLVMValueRef lb_integer_division(lbProcedure *p, LLVMValueRef lhs, L lb_start_block(p, edge_case_block); - switch (behaviour) { case IntegerDivisionByZero_Trap: lb_call_intrinsic(p, "llvm.trap", nullptr, 0, nullptr, 0); @@ -1209,17 +1212,17 @@ gb_internal LLVMValueRef lb_integer_division(lbProcedure *p, LLVMValueRef lhs, L incoming_values[1] = all_bits; break; } + LLVMValueRef res = nullptr; lb_emit_jump(p, done_block); lb_start_block(p, done_block); - LLVMValueRef res = incoming_values[0]; switch (behaviour) { case IntegerDivisionByZero_Trap: - case IntegerDivisionByZero_Self: res = incoming_values[0]; break; + case IntegerDivisionByZero_Self: case IntegerDivisionByZero_Zero: case IntegerDivisionByZero_AllBits: res = LLVMBuildPhi(p->builder, type, ""); @@ -1228,6 +1231,9 @@ gb_internal LLVMValueRef lb_integer_division(lbProcedure *p, LLVMValueRef lhs, L incoming_blocks[0] = p->curr_block->preds[0]->block; incoming_blocks[1] = p->curr_block->preds[1]->block; + GB_ASSERT(incoming_blocks[0] == safe_block->block); + GB_ASSERT(incoming_blocks[1] == edge_case_block->block); + LLVMAddIncoming(res, incoming_values, incoming_blocks, 2); break; } @@ -1235,7 +1241,7 @@ gb_internal LLVMValueRef lb_integer_division(lbProcedure *p, LLVMValueRef lhs, L return res; } -gb_internal LLVMValueRef lb_integer_division_intrinsics(lbProcedure *p, LLVMValueRef lhs, LLVMValueRef rhs, LLVMValueRef scale, Type *platform_type, char const *name) { +gb_internal LLVMValueRef lb_integer_division_fixed_point_intrinsics(lbProcedure *p, LLVMValueRef lhs, LLVMValueRef rhs, LLVMValueRef scale, Type *platform_type, char const *name) { LLVMTypeRef type = LLVMTypeOf(rhs); GB_ASSERT(LLVMTypeOf(lhs) == type); @@ -1305,13 +1311,13 @@ gb_internal LLVMValueRef lb_integer_division_intrinsics(lbProcedure *p, LLVMValu lb_emit_jump(p, done_block); lb_start_block(p, done_block); - LLVMValueRef res = incoming_values[0]; + LLVMValueRef res = nullptr; switch (behaviour) { case IntegerDivisionByZero_Trap: - case IntegerDivisionByZero_Self: res = incoming_values[0]; break; + case IntegerDivisionByZero_Self: case IntegerDivisionByZero_Zero: case IntegerDivisionByZero_AllBits: res = LLVMBuildPhi(p->builder, type, ""); @@ -1418,9 +1424,9 @@ gb_internal LLVMValueRef lb_integer_modulo(lbProcedure *p, LLVMValueRef lhs, LLV switch (behaviour) { case IntegerDivisionByZero_Trap: - case IntegerDivisionByZero_Self: res = incoming_values[0]; break; + case IntegerDivisionByZero_Self: case IntegerDivisionByZero_Zero: case IntegerDivisionByZero_AllBits: res = LLVMBuildPhi(p->builder, type, ""); @@ -2502,7 +2508,6 @@ gb_internal lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) { } for (Type *vt : dst->Union.variants) { if (src_type == t_llvm_bool && is_type_boolean(vt)) { - value = lb_emit_conv(p, value, vt); lbAddr parent = lb_add_local_generated(p, t, true); lb_emit_store_union_variant(p, parent.addr, value, vt); return lb_addr_load(p, parent); @@ -2563,10 +2568,11 @@ gb_internal lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) { Type *dt = t; + TEMPORARY_ALLOCATOR_GUARD(); + GB_ASSERT(is_type_struct(st) || is_type_raw_union(st)); Selection sel = {}; - sel.index.allocator = heap_allocator(); - defer (array_free(&sel.index)); + sel.index.allocator = temporary_allocator(); if (lookup_subtype_polymorphic_selection(t, src_type, &sel)) { if (sel.entity == nullptr) { GB_PANIC("invalid subtype cast %s -> ", type_to_string(src_type), type_to_string(t)); @@ -3929,6 +3935,20 @@ gb_internal lbValue lb_build_expr(lbProcedure *p, Ast *expr) { return res; } +gb_internal Type *lb_build_expr_original_const_type(Ast *expr) { + expr = unparen_expr(expr); + Type *type = type_of_expr(expr); + if (is_type_union(type)) { + if (expr->kind == Ast_CallExpr) { + if (expr->CallExpr.proc->tav.mode == Addressing_Type) { + Type *res = lb_build_expr_original_const_type(expr->CallExpr.args[0]); + return res; + } + } + } + return type_of_expr(expr); +} + gb_internal lbValue lb_build_expr_internal(lbProcedure *p, Ast *expr) { lbModule *m = p->module; @@ -3940,9 +3960,11 @@ gb_internal lbValue lb_build_expr_internal(lbProcedure *p, Ast *expr) { GB_ASSERT_MSG(tv.mode != Addressing_Invalid, "invalid expression '%s' (tv.mode = %d, tv.type = %s) @ %s\n Current Proc: %.*s : %s", expr_to_string(expr), tv.mode, type_to_string(tv.type), token_pos_to_string(expr_pos), LIT(p->name), type_to_string(p->type)); + if (tv.value.kind != ExactValue_Invalid) { + Type *original_type = lb_build_expr_original_const_type(expr); // NOTE(bill): Short on constant values - return lb_const_value(p->module, type, tv.value, LB_CONST_CONTEXT_DEFAULT_ALLOW_LOCAL); + return lb_const_value(p->module, type, tv.value, LB_CONST_CONTEXT_DEFAULT_ALLOW_LOCAL, original_type); } else if (tv.mode == Addressing_Type) { // NOTE(bill, 2023-01-16): is this correct? I hope so at least return lb_typeid(m, tv.type); @@ -4023,7 +4045,7 @@ gb_internal lbValue lb_build_expr_internal(lbProcedure *p, Ast *expr) { TypeAndValue tav = type_and_value_of_expr(expr); GB_ASSERT(tav.mode == Addressing_Constant); - return lb_const_value(p->module, type, tv.value); + return lb_const_value(p->module, type, tv.value, LB_CONST_CONTEXT_DEFAULT_ALLOW_LOCAL, tv.type); case_end; case_ast_node(se, SelectorCallExpr, expr); @@ -4304,7 +4326,7 @@ gb_internal lbAddr lb_build_addr_from_entity(lbProcedure *p, Entity *e, Ast *exp GB_ASSERT(e != nullptr); if (e->kind == Entity_Constant) { Type *t = default_type(type_of_expr(expr)); - lbValue v = lb_const_value(p->module, t, e->Constant.value); + lbValue v = lb_const_value(p->module, t, e->Constant.value, LB_CONST_CONTEXT_DEFAULT_NO_LOCAL, e->type); if (LLVMIsConstant(v.value)) { lbAddr g = lb_add_global_generated_from_procedure(p, t, v); return g; @@ -5763,11 +5785,11 @@ gb_internal lbAddr lb_build_addr_internal(lbProcedure *p, Ast *expr) { if (is_type_union(t)) { Type *type = type_of_expr(expr); lbAddr v = lb_add_local_generated(p, type, false); - lb_addr_store(p, v, lb_emit_union_cast(p, lb_build_expr(p, ta->expr), type, pos)); + lb_addr_store(p, v, lb_emit_union_cast(p, e, type, pos)); return v; } else if (is_type_any(t)) { Type *type = type_of_expr(expr); - return lb_emit_any_cast_addr(p, lb_build_expr(p, ta->expr), type, pos); + return lb_emit_any_cast_addr(p, e, type, pos); } else { GB_PANIC("TODO(bill): type assertion %s", type_to_string(e.type)); } diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index 49a04641c..4ebb40d96 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -15,7 +15,9 @@ gb_global isize lb_global_type_info_member_offsets_index = 0; gb_global isize lb_global_type_info_member_usings_index = 0; gb_global isize lb_global_type_info_member_tags_index = 0; -gb_internal void lb_init_module(lbModule *m, Checker *c) { +gb_internal WORKER_TASK_PROC(lb_init_module_worker_proc) { + lbModule *m = cast(lbModule *)data; + Checker *c = m->checker; m->info = &c->info; @@ -46,6 +48,12 @@ gb_internal void lb_init_module(lbModule *m, Checker *c) { } module_name = gb_string_appendc(module_name, "builtin"); } + if (m->polymorphic_module == m) { + if (gb_string_length(module_name)) { + module_name = gb_string_appendc(module_name, "-"); + } + module_name = gb_string_appendc(module_name, "$parapoly"); + } m->module_name = module_name; m->ctx = LLVMContextCreate(); @@ -89,15 +97,19 @@ gb_internal void lb_init_module(lbModule *m, Checker *c) { map_init(&m->function_type_map); string_map_init(&m->gen_procs); if (USE_SEPARATE_MODULES) { - array_init(&m->procedures_to_generate, a, 0, 1<<10); + mpsc_init(&m->procedures_to_generate, a); map_init(&m->procedure_values, 1<<11); + array_init(&m->generated_procedures, a, 0, 1<<10); } else { - array_init(&m->procedures_to_generate, a, 0, c->info.all_procedures.count); + mpsc_init(&m->procedures_to_generate, a); map_init(&m->procedure_values, c->info.all_procedures.count*2); + array_init(&m->generated_procedures, a, 0, c->info.all_procedures.count*2); } + + array_init(&m->global_procedures_to_create, a, 0, 1024); array_init(&m->global_types_to_create, a, 0, 1024); - array_init(&m->missing_procedures_to_check, a, 0, 16); + mpsc_init(&m->missing_procedures_to_check, a); map_init(&m->debug_values); string_map_init(&m->objc_classes); @@ -113,6 +125,15 @@ gb_internal void lb_init_module(lbModule *m, Checker *c) { m->const_dummy_builder = LLVMCreateBuilderInContext(m->ctx); + return 0; +} + +gb_internal void lb_init_module(lbModule *m, bool do_threading) { + if (do_threading) { + thread_pool_add_task(lb_init_module_worker_proc, m); + } else { + lb_init_module_worker_proc(m); + } } gb_internal bool lb_init_generator(lbGenerator *gen, Checker *c) { @@ -125,6 +146,10 @@ gb_internal bool lb_init_generator(lbGenerator *gen, Checker *c) { return false; } + isize thread_count = gb_max(build_context.thread_count, 1); + isize worker_count = thread_count-1; + bool do_threading = !!(LLVMIsMultithreaded() && USE_SEPARATE_MODULES && MULTITHREAD_OBJECT_GENERATION && worker_count > 0); + String init_fullpath = c->parser->init_fullpath; linker_data_init(gen, &c->info, init_fullpath); @@ -136,7 +161,6 @@ gb_internal bool lb_init_generator(lbGenerator *gen, Checker *c) { map_init(&gen->modules, gen->info->packages.count*2); map_init(&gen->modules_through_ctx, gen->info->packages.count*2); - map_init(&gen->anonymous_proc_lits, 1024); if (USE_SEPARATE_MODULES) { bool module_per_file = build_context.module_per_file && build_context.optimization_level <= 0; @@ -145,26 +169,94 @@ gb_internal bool lb_init_generator(lbGenerator *gen, Checker *c) { auto m = gb_alloc_item(permanent_allocator(), lbModule); m->pkg = pkg; m->gen = gen; + m->checker = c; map_set(&gen->modules, cast(void *)pkg, m); - lb_init_module(m, c); - if (!module_per_file) { + lb_init_module(m, do_threading); + + if (LLVM_WEAK_MONOMORPHIZATION) { + auto pm = gb_alloc_item(permanent_allocator(), lbModule); + pm->pkg = pkg; + pm->gen = gen; + pm->checker = c; + m->polymorphic_module = pm; + pm->polymorphic_module = pm; + + map_set(&gen->modules, cast(void *)pm, pm); // point to itself just add it to the list + + lb_init_module(pm, do_threading); + } + + bool allow_for_per_file = pkg->kind == Package_Runtime || module_per_file; + + #if 0 + if (!allow_for_per_file) { + if (pkg->files.count >= 20) { + isize proc_count = 0; + for (Entity *e : gen->info->entities) { + if (e->kind != Entity_Procedure) { + continue; + } + if (e->Procedure.is_foreign) { + continue; + } + if (e->pkg == pkg) { + proc_count += 1; + } + } + + if (proc_count >= 300) { + allow_for_per_file = true; + } + } + } + #endif + + if (!allow_for_per_file) { continue; } // NOTE(bill): Probably per file is not a good idea, so leave this for later for (AstFile *file : pkg->files) { - auto m = gb_alloc_item(permanent_allocator(), lbModule); + auto m = gb_alloc_item(permanent_allocator(), lbModule); m->file = file; - m->pkg = pkg; - m->gen = gen; + m->pkg = pkg; + m->gen = gen; + m->checker = c; map_set(&gen->modules, cast(void *)file, m); - lb_init_module(m, c); + lb_init_module(m, do_threading); + + + if (LLVM_WEAK_MONOMORPHIZATION) { + auto pm = gb_alloc_item(permanent_allocator(), lbModule); + pm->file = file; + pm->pkg = pkg; + pm->gen = gen; + pm->checker = c; + m->polymorphic_module = pm; + pm->polymorphic_module = pm; + + map_set(&gen->modules, cast(void *)pm, pm); // point to itself just add it to the list + + lb_init_module(pm, do_threading); + } } } + + if (LLVM_WEAK_MONOMORPHIZATION) { + lbModule *m = gb_alloc_item(permanent_allocator(), lbModule); + gen->equal_module = m; + m->gen = gen; + m->checker = c; + map_set(&gen->modules, cast(void *)m, m); // point to itself just add it to the list + lb_init_module(m, do_threading); + } } gen->default_module.gen = gen; + gen->default_module.checker = c; map_set(&gen->modules, cast(void *)1, &gen->default_module); - lb_init_module(&gen->default_module, c); + lb_init_module(&gen->default_module, do_threading); + + thread_pool_wait(); for (auto const &entry : gen->modules) { lbModule *m = entry.value; @@ -403,9 +495,9 @@ gb_internal lbModule *lb_module_of_expr(lbGenerator *gen, Ast *expr) { return &gen->default_module; } -gb_internal lbModule *lb_module_of_entity(lbGenerator *gen, Entity *e) { - GB_ASSERT(e != nullptr); +gb_internal lbModule *lb_module_of_entity_internal(lbGenerator *gen, Entity *e, lbModule *curr_module) { lbModule **found = nullptr; + if (e->kind == Entity_Procedure && e->decl_info && e->decl_info->code_gen_module) { @@ -428,6 +520,22 @@ gb_internal lbModule *lb_module_of_entity(lbGenerator *gen, Entity *e) { return &gen->default_module; } + +gb_internal lbModule *lb_module_of_entity(lbGenerator *gen, Entity *e, lbModule *curr_module) { + GB_ASSERT(e != nullptr); + GB_ASSERT(curr_module != nullptr); + lbModule *m = lb_module_of_entity_internal(gen, e, curr_module); + + if (USE_SEPARATE_MODULES) { + if (e->kind == Entity_Procedure && e->Procedure.generated_from_polymorphic) { + if (m->polymorphic_module) { + return m->polymorphic_module; + } + } + } + return m; +} + gb_internal lbAddr lb_addr(lbValue addr) { lbAddr v = {lbAddr_Default, addr}; return v; @@ -1408,8 +1516,11 @@ gb_internal lbValue lb_emit_union_tag_ptr(lbProcedure *p, lbValue u) { unsigned element_count = LLVMCountStructElementTypes(uvt); GB_ASSERT_MSG(element_count >= 2, "element_count=%u (%s) != (%s)", element_count, type_to_string(ut), LLVMPrintTypeToString(uvt)); + LLVMValueRef ptr = u.value; + ptr = LLVMBuildPointerCast(p->builder, ptr, LLVMPointerType(uvt, 0), ""); + lbValue tag_ptr = {}; - tag_ptr.value = LLVMBuildStructGEP2(p->builder, uvt, u.value, 1, ""); + tag_ptr.value = LLVMBuildStructGEP2(p->builder, uvt, ptr, 1, ""); tag_ptr.type = alloc_type_pointer(tag_type); return tag_ptr; } @@ -1634,8 +1745,92 @@ gb_internal LLVMTypeRef lb_type_internal_for_procedures_raw(lbModule *m, Type *t map_set(&m->func_raw_types, type, new_abi_fn_type); return new_abi_fn_type; +} + + +gb_internal LLVMTypeRef lb_type_internal_union_block_type(lbModule *m, Type *type) { + GB_ASSERT(type->kind == Type_Union); + + if (type->Union.variants.count <= 0) { + return nullptr; + } + if (type->Union.variants.count == 1) { + return lb_type(m, type->Union.variants[0]); + } + + i64 align = type_align_of(type); + + unsigned block_size = cast(unsigned)type->Union.variant_block_size; + if (block_size == 0) { + return lb_type_padding_filler(m, block_size, align); + } + + bool all_pointers = align == build_context.ptr_size; + for (isize i = 0; all_pointers && i < type->Union.variants.count; i++) { + Type *t = type->Union.variants[i]; + if (!is_type_internally_pointer_like(t)) { + all_pointers = false; + } + } + if (all_pointers) { + return lb_type(m, t_rawptr); + } + + { + Type *pt = type->Union.variants[0]; + for (isize i = 1; i < type->Union.variants.count; i++) { + Type *t = type->Union.variants[i]; + if (!are_types_identical(pt, t)) { + goto end_check_for_all_the_same; + } + } + return lb_type(m, pt); + } end_check_for_all_the_same:; + + { + Type *first_different = nullptr; + for (isize i = 0; i < type->Union.variants.count; i++) { + Type *t = type->Union.variants[i]; + if (type_size_of(t) == 0) { + continue; + } + if (first_different == nullptr) { + first_different = t; + } else if (!are_types_identical(first_different, t)) { + goto end_rest_zero_except_one; + } + } + if (first_different != nullptr) { + return lb_type(m, first_different); + } + } end_rest_zero_except_one:; + + // { + // LLVMTypeRef first_different = nullptr; + // for (isize i = 0; i < type->Union.variants.count; i++) { + // Type *t = type->Union.variants[i]; + // if (type_size_of(t) == 0) { + // continue; + // } + // if (first_different == nullptr) { + // first_different = lb_type(m, base_type(t)); + // } else { + // LLVMTypeRef llvm_t = lb_type(m, base_type(t)); + // if (llvm_t != first_different) { + // goto end_rest_zero_except_one_llvm_like; + // } + // } + // } + // if (first_different != nullptr) { + // return first_different; + // } + // } end_rest_zero_except_one_llvm_like:; + + return lb_type_padding_filler(m, block_size, align); } + + gb_internal LLVMTypeRef lb_type_internal(lbModule *m, Type *type) { LLVMContextRef ctx = m->ctx; i64 size = type_size_of(type); // Check size @@ -2148,27 +2343,24 @@ gb_internal LLVMTypeRef lb_type_internal(lbModule *m, Type *type) { return LLVMStructTypeInContext(ctx, fields, gb_count_of(fields), false); } - unsigned block_size = cast(unsigned)type->Union.variant_block_size; - auto fields = array_make<LLVMTypeRef>(temporary_allocator(), 0, 3); if (is_type_union_maybe_pointer(type)) { LLVMTypeRef variant = lb_type(m, type->Union.variants[0]); array_add(&fields, variant); - } else { - LLVMTypeRef block_type = nullptr; + } else if (type->Union.variants.count == 1) { + LLVMTypeRef block_type = lb_type(m, type->Union.variants[0]); - bool all_pointers = align == build_context.ptr_size; - for (isize i = 0; all_pointers && i < type->Union.variants.count; i++) { - Type *t = type->Union.variants[i]; - if (!is_type_internally_pointer_like(t)) { - all_pointers = false; - } - } - if (all_pointers) { - block_type = lb_type(m, t_rawptr); - } else { - block_type = lb_type_padding_filler(m, block_size, align); + LLVMTypeRef tag_type = lb_type(m, union_tag_type(type)); + array_add(&fields, block_type); + array_add(&fields, tag_type); + i64 used_size = lb_sizeof(block_type) + lb_sizeof(tag_type); + i64 padding = size - used_size; + if (padding > 0) { + LLVMTypeRef padding_type = lb_type_padding_filler(m, padding, align); + array_add(&fields, padding_type); } + } else { + LLVMTypeRef block_type = lb_type_internal_union_block_type(m, type); LLVMTypeRef tag_type = lb_type(m, union_tag_type(type)); array_add(&fields, block_type); @@ -2355,29 +2547,9 @@ gb_internal LLVMAttributeRef lb_create_enum_attribute_with_type(LLVMContextRef c unsigned kind = 0; String s = make_string_c(name); - #if ODIN_LLVM_MINIMUM_VERSION_12 - kind = LLVMGetEnumAttributeKindForName(name, s.len); - GB_ASSERT_MSG(kind != 0, "unknown attribute: %s", name); - return LLVMCreateTypeAttribute(ctx, kind, type); - #else - // 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; - } - - - kind = LLVMGetEnumAttributeKindForName(name, s.len); - GB_ASSERT_MSG(kind != 0, "unknown attribute: %s", name); - return LLVMCreateEnumAttribute(ctx, kind, 0); - #endif + kind = LLVMGetEnumAttributeKindForName(name, s.len); + GB_ASSERT_MSG(kind != 0, "unknown attribute: %s", name); + return LLVMCreateTypeAttribute(ctx, kind, type); } gb_internal LLVMAttributeRef lb_create_enum_attribute(LLVMContextRef ctx, char const *name, u64 value) { @@ -2420,6 +2592,20 @@ gb_internal void lb_add_proc_attribute_at_index(lbProcedure *p, isize index, cha lb_add_proc_attribute_at_index(p, index, name, 0); } +gb_internal void lb_add_proc_attribute_at_index_with_string(lbProcedure *p, isize index, String const &name, String const &value) { + LLVMAttributeRef attr = lb_create_string_attribute(p->module->ctx, name, value); + GB_ASSERT(attr != nullptr); + LLVMAddAttributeAtIndex(p->value, cast(unsigned)index, attr); +} + +gb_internal void lb_add_nocapture_proc_attribute_at_index(lbProcedure *p, isize index) { + #if LLVM_VERSION_MAJOR >= 21 + lb_add_proc_attribute_at_index_with_string(p, index, make_string_c("captures"), make_string_c("none")); + #else + lb_add_proc_attribute_at_index(p, index, "nocapture"); + #endif +} + gb_internal void lb_add_attribute_to_proc(lbModule *m, LLVMValueRef proc_value, char const *name, u64 value=0) { LLVMAddAttributeAtIndex(proc_value, LLVMAttributeIndex_FunctionIndex, lb_create_enum_attribute(m->ctx, name, value)); } @@ -2809,11 +2995,16 @@ gb_internal lbValue lb_find_or_add_entity_string_byte_slice_with_type(lbModule * } else { ptr = LLVMConstNull(lb_type(m, t_u8_ptr)); } + i64 align = MINIMUM_SLICE_ALIGNMENT; if (!is_type_u8_slice(slice_type)) { Type *bt = base_type(slice_type); Type *elem = bt->Slice.elem; i64 sz = type_size_of(elem); + align = gb_max(type_align_of(elem), align); GB_ASSERT(sz > 0); + GB_ASSERT(align > 0); + + LLVMSetAlignment(global_data, (u32)align); ptr = LLVMConstPointerCast(ptr, lb_type(m, alloc_type_pointer(elem))); data_len /= sz; } @@ -2864,11 +3055,16 @@ gb_internal lbValue lb_find_or_add_entity_string16_slice_with_type(lbModule *m, } else { ptr = LLVMConstNull(lb_type(m, t_u8_ptr)); } + i64 align = MINIMUM_SLICE_ALIGNMENT; if (!is_type_u16_slice(slice_type)) { Type *bt = base_type(slice_type); Type *elem = bt->Slice.elem; i64 sz = type_size_of(elem); + align = gb_max(type_align_of(elem), align); GB_ASSERT(sz > 0); + GB_ASSERT(align > 0); + + LLVMSetAlignment(global_data, (u32)align); ptr = LLVMConstPointerCast(ptr, lb_type(m, alloc_type_pointer(elem))); data_len /= sz; } @@ -2914,7 +3110,7 @@ gb_internal lbValue lb_find_ident(lbProcedure *p, lbModule *m, Entity *e, Ast *e return lb_find_procedure_value_from_entity(m, e); } if (USE_SEPARATE_MODULES) { - lbModule *other_module = lb_module_of_entity(m->gen, e); + lbModule *other_module = lb_module_of_entity(m->gen, e, m); if (other_module != m) { String name = lb_get_entity_name(other_module, e); @@ -2962,7 +3158,7 @@ gb_internal lbValue lb_find_procedure_value_from_entity(lbModule *m, Entity *e) lbModule *other_module = m; if (USE_SEPARATE_MODULES) { - other_module = lb_module_of_entity(gen, e); + other_module = lb_module_of_entity(gen, e, m); } if (other_module == m) { debugf("Missing Procedure (lb_find_procedure_value_from_entity): %.*s module %p\n", LIT(e->token.string), m); @@ -2979,9 +3175,6 @@ gb_internal lbValue lb_find_procedure_value_from_entity(lbModule *m, Entity *e) } if (ignore_body) { - mutex_lock(&gen->anonymous_proc_lits_mutex); - defer (mutex_unlock(&gen->anonymous_proc_lits_mutex)); - GB_ASSERT(other_module != nullptr); rw_mutex_shared_lock(&other_module->values_mutex); auto *found = map_get(&other_module->values, e); @@ -2989,10 +3182,10 @@ gb_internal lbValue lb_find_procedure_value_from_entity(lbModule *m, Entity *e) if (found == nullptr) { // THIS IS THE RACE CONDITION lbProcedure *missing_proc_in_other_module = lb_create_procedure(other_module, e, false); - array_add(&other_module->missing_procedures_to_check, missing_proc_in_other_module); + mpsc_enqueue(&other_module->missing_procedures_to_check, missing_proc_in_other_module); } } else { - array_add(&m->missing_procedures_to_check, missing_proc); + mpsc_enqueue(&m->missing_procedures_to_check, missing_proc); } rw_mutex_shared_lock(&m->values_mutex); @@ -3010,17 +3203,15 @@ gb_internal lbValue lb_find_procedure_value_from_entity(lbModule *m, Entity *e) gb_internal lbValue lb_generate_anonymous_proc_lit(lbModule *m, String const &prefix_name, Ast *expr, lbProcedure *parent) { lbGenerator *gen = m->gen; + gb_unused(gen); - mutex_lock(&gen->anonymous_proc_lits_mutex); - defer (mutex_unlock(&gen->anonymous_proc_lits_mutex)); + ast_node(pl, ProcLit, expr); - TokenPos pos = ast_token(expr).pos; - lbProcedure **found = map_get(&gen->anonymous_proc_lits, expr); - if (found) { - return lb_find_procedure_value_from_entity(m, (*found)->entity); + if (pl->decl->entity.load() != nullptr) { + return lb_find_procedure_value_from_entity(m, pl->decl->entity.load()); } - ast_node(pl, ProcLit, expr); + TokenPos pos = ast_token(expr).pos; // NOTE(bill): Generate a new name // parent$count @@ -3039,30 +3230,51 @@ gb_internal lbValue lb_generate_anonymous_proc_lit(lbModule *m, String const &pr token.string = name; Entity *e = alloc_entity_procedure(nullptr, token, type, pl->tags); e->file = expr->file(); + e->scope = e->file->scope; + + lbModule *target_module = m; + GB_ASSERT(target_module != nullptr); // NOTE(bill): this is to prevent a race condition since these procedure literals can be created anywhere at any time - pl->decl->code_gen_module = m; + pl->decl->code_gen_module = target_module; e->decl_info = pl->decl; - pl->decl->entity = e; e->parent_proc_decl = pl->decl->parent; e->Procedure.is_anonymous = true; e->flags |= EntityFlag_ProcBodyChecked; - lbProcedure *p = lb_create_procedure(m, e); - GB_ASSERT(e->code_gen_module == m); + pl->decl->entity.store(e); + - lbValue value = {}; - value.value = p->value; - value.type = p->type; + if (target_module != m) { + rw_mutex_shared_lock(&target_module->values_mutex); + lbValue *found = map_get(&target_module->values, e); + rw_mutex_shared_unlock(&target_module->values_mutex); + if (found == nullptr) { + lbProcedure *missing_proc_in_target_module = lb_create_procedure(target_module, e, false); + mpsc_enqueue(&target_module->missing_procedures_to_check, missing_proc_in_target_module); + } - map_set(&gen->anonymous_proc_lits, expr, p); - array_add(&m->procedures_to_generate, p); - if (parent != nullptr) { - array_add(&parent->children, p); + lbProcedure *p = lb_create_procedure(m, e, true); + + lbValue value = {}; + value.value = p->value; + value.type = p->type; + return value; } else { - string_map_set(&m->members, name, value); + lbProcedure *p = lb_create_procedure(m, e); + + lbValue value = {}; + value.value = p->value; + value.type = p->type; + + mpsc_enqueue(&m->procedures_to_generate, p); + if (parent != nullptr) { + array_add(&parent->children, p); + } else { + string_map_set(&m->members, name, value); + } + return value; } - return value; } @@ -3071,11 +3283,18 @@ gb_internal lbAddr lb_add_global_generated_with_name(lbModule *m, Type *type, lb GB_ASSERT(type != nullptr); type = default_type(type); + LLVMTypeRef actual_type = lb_type(m, type); + if (value.value != nullptr) { + LLVMTypeRef value_type = LLVMTypeOf(value.value); + GB_ASSERT_MSG(lb_sizeof(actual_type) == lb_sizeof(value_type), "%s vs %s", LLVMPrintTypeToString(actual_type), LLVMPrintTypeToString(value_type)); + actual_type = value_type; + } + Scope *scope = nullptr; Entity *e = alloc_entity_variable(scope, make_token_ident(name), type); lbValue g = {}; g.type = alloc_type_pointer(type); - g.value = LLVMAddGlobal(m->mod, lb_type(m, type), alloc_cstring(temporary_allocator(), name)); + g.value = LLVMAddGlobal(m->mod, actual_type, alloc_cstring(temporary_allocator(), name)); if (value.value != nullptr) { GB_ASSERT_MSG(LLVMIsConstant(value.value), LLVMPrintValueToString(value.value)); LLVMSetInitializer(g.value, value.value); @@ -3083,6 +3302,8 @@ gb_internal lbAddr lb_add_global_generated_with_name(lbModule *m, Type *type, lb LLVMSetInitializer(g.value, LLVMConstNull(lb_type(m, type))); } + g.value = LLVMConstPointerCast(g.value, lb_type(m, g.type)); + lb_add_entity(m, e, g); lb_add_member(m, name, g); @@ -3145,7 +3366,7 @@ gb_internal lbValue lb_find_value_from_entity(lbModule *m, Entity *e) { } if (USE_SEPARATE_MODULES) { - lbModule *other_module = lb_module_of_entity(m->gen, e); + lbModule *other_module = lb_module_of_entity(m->gen, e, m); bool is_external = other_module != m; if (!is_external) { diff --git a/src/llvm_backend_opt.cpp b/src/llvm_backend_opt.cpp index 8d5cfcb70..4971b1f10 100644 --- a/src/llvm_backend_opt.cpp +++ b/src/llvm_backend_opt.cpp @@ -48,13 +48,6 @@ gb_internal void lb_populate_function_pass_manager_specific(lbModule *m, LLVMPas // return LLVMIsAAllocaInst(value) != nullptr; // } - -#if LLVM_VERSION_MAJOR < 12 -#define LLVM_ADD_CONSTANT_VALUE_PASS(fpm) LLVMAddConstantPropagationPass(fpm) -#else -#define LLVM_ADD_CONSTANT_VALUE_PASS(fpm) -#endif - gb_internal bool lb_opt_ignore(i32 optimization_level) { return optimization_level < 0; } @@ -70,7 +63,6 @@ gb_internal void lb_basic_populate_function_pass_manager(LLVMPassManagerRef fpm, } else { LLVMAddPromoteMemoryToRegisterPass(fpm); LLVMAddMergedLoadStoreMotionPass(fpm); - LLVM_ADD_CONSTANT_VALUE_PASS(fpm); if (!build_context.ODIN_DEBUG) { LLVMAddEarlyCSEPass(fpm); } @@ -135,10 +127,8 @@ gb_internal void lb_populate_function_pass_manager_specific(lbModule *m, LLVMPas LLVMAddMemCpyOptPass(fpm); LLVMAddPromoteMemoryToRegisterPass(fpm); LLVMAddMergedLoadStoreMotionPass(fpm); - LLVM_ADD_CONSTANT_VALUE_PASS(fpm); LLVMAddEarlyCSEPass(fpm); - LLVM_ADD_CONSTANT_VALUE_PASS(fpm); LLVMAddMergedLoadStoreMotionPass(fpm); LLVMAddPromoteMemoryToRegisterPass(fpm); LLVMAddCFGSimplificationPass(fpm); @@ -183,7 +173,6 @@ gb_internal void lb_add_function_simplifcation_passes(LLVMPassManagerRef mpm, i3 LLVMAddBitTrackingDCEPass(mpm); LLVMAddJumpThreadingPass(mpm); - LLVM_ADD_CONSTANT_VALUE_PASS(mpm); LLVMAddLICMPass(mpm); LLVMAddLoopRerollPass(mpm); @@ -249,7 +238,6 @@ gb_internal void lb_populate_module_pass_manager(LLVMTargetMachineRef target_mac if (optimization_level >= 2) { LLVMAddEarlyCSEPass(mpm); - LLVM_ADD_CONSTANT_VALUE_PASS(mpm); LLVMAddLICMPass(mpm); LLVMAddLoopUnswitchPass(mpm); LLVMAddCFGSimplificationPass(mpm); diff --git a/src/llvm_backend_passes.cpp b/src/llvm_backend_passes.cpp index bea95ce8e..e9edbace7 100644 --- a/src/llvm_backend_passes.cpp +++ b/src/llvm_backend_passes.cpp @@ -263,7 +263,7 @@ function( ), verify )"); -#else +#else // LLVM 20 & 21 (same config) array_add(&passes, u8R"( annotation2metadata, forceattrs, @@ -656,7 +656,7 @@ function( ), verify )"); -#else +#else // LLVM 20 & 21 (same config) array_add(&passes, u8R"( annotation2metadata, forceattrs, @@ -1052,7 +1052,7 @@ function( ), verify )"); -#else +#else // LLVM 20 & 21 (same config) array_add(&passes, u8R"( annotation2metadata, forceattrs, @@ -1192,4 +1192,4 @@ verify #endif break; - }
\ No newline at end of file + } diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index f2e6662c8..27167aefd 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -84,7 +84,7 @@ gb_internal lbProcedure *lb_create_procedure(lbModule *m, Entity *entity, bool i String link_name = {}; if (ignore_body) { - lbModule *other_module = lb_module_of_entity(m->gen, entity); + lbModule *other_module = lb_module_of_entity(m->gen, entity, m); link_name = lb_get_entity_name(other_module, entity); } else { link_name = lb_get_entity_name(m, entity); @@ -99,7 +99,6 @@ gb_internal lbProcedure *lb_create_procedure(lbModule *m, Entity *entity, bool i } } - lbProcedure *p = gb_alloc_item(permanent_allocator(), lbProcedure); p->module = m; @@ -241,8 +240,6 @@ gb_internal lbProcedure *lb_create_procedure(lbModule *m, Entity *entity, bool i } } } - lb_set_linkage_from_entity_flags(p->module, p->value, entity->flags); - if (p->is_foreign) { lb_set_wasm_procedure_import_attributes(p->value, entity, p->name); @@ -273,7 +270,7 @@ gb_internal lbProcedure *lb_create_procedure(lbModule *m, Entity *entity, bool i } if (e->flags&EntityFlag_NoCapture) { if (is_type_internally_pointer_like(e->type)) { - lb_add_proc_attribute_at_index(p, offset+parameter_index, "nocapture"); + lb_add_nocapture_proc_attribute_at_index(p, offset+parameter_index); } } parameter_index += 1; @@ -285,6 +282,7 @@ gb_internal lbProcedure *lb_create_procedure(lbModule *m, Entity *entity, bool i LLVMSetLinkage(p->value, LLVMExternalLinkage); } + lb_set_linkage_from_entity_flags(p->module, p->value, entity->flags); if (m->debug_builder) { // Debug Information Type *bt = base_type(p->type); @@ -431,7 +429,7 @@ gb_internal lbProcedure *lb_create_dummy_procedure(lbModule *m, String link_name if (pt->Proc.calling_convention == ProcCC_Odin) { lb_add_proc_attribute_at_index(p, offset+parameter_index, "noalias"); lb_add_proc_attribute_at_index(p, offset+parameter_index, "nonnull"); - lb_add_proc_attribute_at_index(p, offset+parameter_index, "nocapture"); + lb_add_nocapture_proc_attribute_at_index(p, offset+parameter_index); } return p; } @@ -798,9 +796,8 @@ gb_internal void lb_end_procedure_body(lbProcedure *p) { gb_internal void lb_build_nested_proc(lbProcedure *p, AstProcLit *pd, Entity *e) { GB_ASSERT(pd->body != nullptr); lbModule *m = p->module; - auto *min_dep_set = &m->info->minimum_dependency_set; - if (ptr_set_exists(min_dep_set, e) == false) { + if (e->min_dep_count.load(std::memory_order_relaxed) == 0) { // NOTE(bill): Nothing depends upon it so doesn't need to be built return; } @@ -836,7 +833,7 @@ gb_internal void lb_build_nested_proc(lbProcedure *p, AstProcLit *pd, Entity *e) lb_add_entity(m, e, value); array_add(&p->children, nested_proc); - array_add(&m->procedures_to_generate, nested_proc); + mpsc_enqueue(&m->procedures_to_generate, nested_proc); } @@ -923,13 +920,14 @@ gb_internal lbValue lb_emit_call_internal(lbProcedure *p, lbValue value, lbValue arg_type != param_type) { LLVMTypeKind arg_kind = LLVMGetTypeKind(arg_type); LLVMTypeKind param_kind = LLVMGetTypeKind(param_type); - if (arg_kind == param_kind && - arg_kind == LLVMPointerTypeKind) { - // NOTE(bill): LLVM's newer `ptr` only type system seems to fail at times - // I don't know why... - args[i] = LLVMBuildPointerCast(p->builder, args[i], param_type, ""); - arg_type = param_type; - continue; + if (arg_kind == param_kind) { + if (arg_kind == LLVMPointerTypeKind) { + // NOTE(bill): LLVM's newer `ptr` only type system seems to fail at times + // I don't know why... + args[i] = LLVMBuildPointerCast(p->builder, args[i], param_type, ""); + arg_type = param_type; + continue; + } } } @@ -2212,7 +2210,7 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu GB_ASSERT(e != nullptr); if (e->parent_proc_decl != nullptr && e->parent_proc_decl->entity != nullptr) { - procedure = e->parent_proc_decl->entity->token.string; + procedure = e->parent_proc_decl->entity.load()->token.string; } else { procedure = str_lit(""); } @@ -2239,7 +2237,7 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu elements[i] = element; } - LLVMValueRef backing_array = llvm_const_array(lb_type(m, t_load_directory_file), elements, count); + LLVMValueRef backing_array = llvm_const_array(m, lb_type(m, t_load_directory_file), elements, count); Type *array_type = alloc_type_array(t_load_directory_file, count); lbAddr backing_array_addr = lb_add_global_generated_from_procedure(p, array_type, {backing_array, array_type}); @@ -2683,7 +2681,7 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu case BuiltinProc_transpose: { lbValue m = lb_build_expr(p, ce->args[0]); - return lb_emit_matrix_tranpose(p, m, tv.type); + return lb_emit_matrix_transpose(p, m, tv.type); } case BuiltinProc_outer_product: @@ -3307,7 +3305,7 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu if (id == BuiltinProc_fixed_point_div || id == BuiltinProc_fixed_point_div_sat) { - res.value = lb_integer_division_intrinsics(p, x.value, y.value, scale.value, platform_type, name); + res.value = lb_integer_division_fixed_point_intrinsics(p, x.value, y.value, scale.value, platform_type, name); } else { LLVMTypeRef types[1] = {lb_type(p->module, platform_type)}; @@ -3754,6 +3752,7 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu case BuiltinProc_objc_register_class: return lb_handle_objc_register_class(p, expr); case BuiltinProc_objc_ivar_get: return lb_handle_objc_ivar_get(p, expr); case BuiltinProc_objc_block: return lb_handle_objc_block(p, expr); + case BuiltinProc_objc_super: return lb_handle_objc_super(p, expr); case BuiltinProc_constant_utf16_cstring: @@ -4123,21 +4122,23 @@ gb_internal lbValue lb_build_call_expr_internal(lbProcedure *p, Ast *expr) { } Ast *proc_expr = unparen_expr(ce->proc); + Entity *proc_entity = entity_of_node(proc_expr); + if (proc_mode == Addressing_Builtin) { - Entity *e = entity_of_node(proc_expr); BuiltinProcId id = BuiltinProc_Invalid; - if (e != nullptr) { - id = cast(BuiltinProcId)e->Builtin.id; + if (proc_entity != nullptr) { + id = cast(BuiltinProcId)proc_entity->Builtin.id; } else { id = BuiltinProc_DIRECTIVE; } return lb_build_builtin_proc(p, expr, tv, id); } + bool is_objc_call = proc_entity && proc_entity->Procedure.is_objc_impl_or_import; + // NOTE(bill): Regular call lbValue value = {}; - Entity *proc_entity = entity_of_node(proc_expr); if (proc_entity != nullptr) { if (proc_entity->flags & EntityFlag_Disabled) { GB_ASSERT(tv.type == nullptr); @@ -4171,11 +4172,13 @@ gb_internal lbValue lb_build_call_expr_internal(lbProcedure *p, Ast *expr) { } } - if (value.value == nullptr) { + if (is_objc_call) { + value.type = proc_tv.type; + } else if (value.value == nullptr) { value = lb_build_expr(p, proc_expr); } - GB_ASSERT(value.value != nullptr); + GB_ASSERT(value.value != nullptr || is_objc_call); Type *proc_type_ = base_type(value.type); GB_ASSERT(proc_type_->kind == Type_Proc); TypeProc *pt = &proc_type_->Proc; @@ -4403,6 +4406,11 @@ gb_internal lbValue lb_build_call_expr_internal(lbProcedure *p, Ast *expr) { isize final_count = is_c_vararg ? args.count : pt->param_count; auto call_args = array_slice(args, 0, final_count); + + if (is_objc_call) { + return lb_handle_objc_auto_send(p, expr, slice(call_args, 0, call_args.count)); + } + return lb_emit_call(p, value, call_args, ce->inlining); } diff --git a/src/llvm_backend_stmt.cpp b/src/llvm_backend_stmt.cpp index 5481ca447..3dbcea4fb 100644 --- a/src/llvm_backend_stmt.cpp +++ b/src/llvm_backend_stmt.cpp @@ -3,8 +3,6 @@ gb_internal void lb_build_constant_value_decl(lbProcedure *p, AstValueDecl *vd) return; } - auto *min_dep_set = &p->module->info->minimum_dependency_set; - for (Ast *ident : vd->names) { GB_ASSERT(ident->kind == Ast_Ident); Entity *e = entity_of_node(ident); @@ -21,7 +19,7 @@ gb_internal void lb_build_constant_value_decl(lbProcedure *p, AstValueDecl *vd) } } - if (!polymorphic_struct && !ptr_set_exists(min_dep_set, e)) { + if (!polymorphic_struct && e->min_dep_count.load(std::memory_order_relaxed) == 0) { continue; } @@ -56,7 +54,7 @@ gb_internal void lb_build_constant_value_decl(lbProcedure *p, AstValueDecl *vd) if (gpd) { rw_mutex_shared_lock(&gpd->mutex); for (Entity *e : gpd->procs) { - if (!ptr_set_exists(min_dep_set, e)) { + if (e->min_dep_count.load(std::memory_order_relaxed) == 0) { continue; } DeclInfo *d = decl_info_of_entity(e); @@ -94,7 +92,7 @@ gb_internal void lb_build_constant_value_decl(lbProcedure *p, AstValueDecl *vd) value.value = nested_proc->value; value.type = nested_proc->type; - array_add(&p->module->procedures_to_generate, nested_proc); + mpsc_enqueue(&p->module->procedures_to_generate, nested_proc); array_add(&p->children, nested_proc); string_map_set(&p->module->members, name, value); } @@ -2180,11 +2178,14 @@ gb_internal void lb_build_static_variables(lbProcedure *p, AstValueDecl *vd) { LLVMSetLinkage(var_global_ref, LLVMInternalLinkage); } - LLVMValueRef vals[2] = { - lb_emit_conv(p, var_global.addr, t_rawptr).value, - lb_typeid(p->module, var_type).value, - }; - LLVMValueRef init = llvm_const_named_struct(p->module, e->type, vals, gb_count_of(vals)); + auto vals = array_make<LLVMValueRef>(temporary_allocator(), 0, 3); + array_add(&vals, lb_emit_conv(p, var_global.addr, t_rawptr).value); + if (build_context.metrics.ptr_size == 4) { + array_add(&vals, LLVMConstNull(lb_type_padding_filler(p->module, 4, 4))); + } + array_add(&vals, lb_typeid(p->module, var_type).value); + + LLVMValueRef init = llvm_const_named_struct(p->module, e->type, vals.data, vals.count); LLVMSetInitializer(global, init); } else { LLVMSetInitializer(global, value.value); diff --git a/src/llvm_backend_type.cpp b/src/llvm_backend_type.cpp index d1e7c0559..382304a4e 100644 --- a/src/llvm_backend_type.cpp +++ b/src/llvm_backend_type.cpp @@ -181,15 +181,9 @@ gb_internal LLVMTypeRef *lb_setup_modified_types_for_type_info(lbModule *m, isiz stypes[0] = lb_type(m, tibt->Struct.fields[0]->type); stypes[1] = lb_type(m, tibt->Struct.fields[1]->type); stypes[2] = lb_type(m, tibt->Struct.fields[2]->type); - isize variant_index = 0; - if (build_context.ptr_size == 8) { - stypes[3] = lb_type(m, t_i32); // padding - stypes[4] = lb_type(m, tibt->Struct.fields[3]->type); - variant_index = 5; - } else { - stypes[3] = lb_type(m, tibt->Struct.fields[3]->type); - variant_index = 4; - } + stypes[3] = lb_type(m, t_i32); // padding + stypes[4] = lb_type(m, tibt->Struct.fields[3]->type); + isize variant_index = 5; LLVMTypeRef *modified_types = gb_alloc_array(heap_allocator(), LLVMTypeRef, Typeid__COUNT); GB_ASSERT(Typeid__COUNT == ut->Union.variants.count); @@ -302,7 +296,7 @@ gb_internal void lb_setup_type_info_data_giant_array(lbModule *m, i64 global_typ (name##_values)[i] = LLVMConstNull(elem); \ } \ } \ - LLVMSetInitializer(name.addr.value, llvm_const_array(elem, name##_values, at->Array.count)); \ + LLVMSetInitializer(name.addr.value, llvm_const_array(m, elem, name##_values, at->Array.count)); \ }) type_info_allocate_values(lb_global_type_info_member_types); @@ -360,16 +354,9 @@ gb_internal void lb_setup_type_info_data_giant_array(lbModule *m, i64 global_typ small_const_values[0] = LLVMConstInt(lb_type(m, t_int), size, true); small_const_values[1] = LLVMConstInt(lb_type(m, t_int), align, true); small_const_values[2] = type_info_flags.value; - - unsigned variant_index = 0; - if (build_context.ptr_size == 8) { - small_const_values[3] = LLVMConstNull(LLVMStructGetTypeAtIndex(stype, 3)); - small_const_values[4] = id.value; - variant_index = 5; - } else { - small_const_values[3] = id.value; - variant_index = 4; - } + small_const_values[3] = LLVMConstNull(LLVMStructGetTypeAtIndex(stype, 3)); + small_const_values[4] = id.value; + unsigned variant_index = 5; LLVMTypeRef full_variant_type = LLVMStructGetTypeAtIndex(stype, variant_index); unsigned full_variant_elem_count = LLVMCountStructElementTypes(full_variant_type); @@ -394,8 +381,9 @@ gb_internal void lb_setup_type_info_data_giant_array(lbModule *m, i64 global_typ String proc_name = {}; if (t->Named.type_name->parent_proc_decl) { DeclInfo *decl = t->Named.type_name->parent_proc_decl; - if (decl->entity && decl->entity->kind == Entity_Procedure) { - proc_name = decl->entity->token.string; + Entity *e = decl->entity.load(); + if (e && e->kind == Entity_Procedure) { + proc_name = e->token.string; } } TokenPos pos = t->Named.type_name->token.pos; @@ -751,8 +739,8 @@ gb_internal void lb_setup_type_info_data_giant_array(lbModule *m, i64 global_typ value_values[i] = lb_const_value(m, t_i64, fields[i]->Constant.value).value; } - LLVMValueRef name_init = llvm_const_array(lb_type(m, t_string), name_values, cast(unsigned)fields.count); - LLVMValueRef value_init = llvm_const_array(lb_type(m, t_type_info_enum_value), value_values, cast(unsigned)fields.count); + LLVMValueRef name_init = llvm_const_array(m, lb_type(m, t_string), name_values, cast(unsigned)fields.count); + LLVMValueRef value_init = llvm_const_array(m, lb_type(m, t_type_info_enum_value), value_values, cast(unsigned)fields.count); LLVMSetInitializer(name_array.value, name_init); LLVMSetInitializer(value_array.value, value_init); LLVMSetGlobalConstant(name_array.value, true); @@ -829,10 +817,10 @@ gb_internal void lb_setup_type_info_data_giant_array(lbModule *m, i64 global_typ { u8 flags = 0; - if (t->Struct.is_packed) flags |= 1<<0; - if (t->Struct.is_raw_union) flags |= 1<<1; - // - if (t->Struct.custom_align) flags |= 1<<3; + if (t->Struct.is_packed) flags |= 1<<0; + if (t->Struct.is_raw_union) flags |= 1<<1; + if (t->Struct.is_all_or_none) flags |= 1<<2; + if (t->Struct.custom_align) flags |= 1<<3; vals[6] = lb_const_int(m, t_u8, flags).value; if (is_type_comparable(t) && !is_type_simple_compare(t)) { diff --git a/src/llvm_backend_utility.cpp b/src/llvm_backend_utility.cpp index f7807364a..9ddbd1f9c 100644 --- a/src/llvm_backend_utility.cpp +++ b/src/llvm_backend_utility.cpp @@ -286,7 +286,14 @@ gb_internal lbValue lb_emit_transmute(lbProcedure *p, lbValue value, Type *t) { } } + bool is_simd_vector_bitcastable = false; if (is_type_simd_vector(src) && is_type_simd_vector(dst)) { + if (!is_type_internally_pointer_like(src->SimdVector.elem) && !is_type_internally_pointer_like(dst->SimdVector.elem)) { + is_simd_vector_bitcastable = true; + } + } + + if (is_simd_vector_bitcastable) { res.value = LLVMBuildBitCast(p->builder, value.value, lb_type(p->module, t), ""); return res; } else if (is_type_array_like(src) && (is_type_simd_vector(dst) || is_type_integer_128bit(dst))) { @@ -974,9 +981,12 @@ gb_internal lbStructFieldRemapping lb_get_struct_remapping(lbModule *m, Type *t) mutex_lock(&m->types_mutex); - auto *field_remapping = map_get(&m->struct_field_remapping, cast(void *)struct_type); + // NOTE(jakub): It's very important to check the type pointer first, + // because two disctinct but similar structs can end up with the same LLVMTypeRef after interning. + // (For example struct{u16,u8} looks identical to LLVM as struct{u16,u8,u8} once padding fields are inserted.) + auto *field_remapping = map_get(&m->struct_field_remapping, cast(void *)t); if (field_remapping == nullptr) { - field_remapping = map_get(&m->struct_field_remapping, cast(void *)t); + field_remapping = map_get(&m->struct_field_remapping, cast(void *)struct_type); } mutex_unlock(&m->types_mutex); @@ -995,6 +1005,7 @@ gb_internal i32 lb_convert_struct_index(lbModule *m, Type *t, i32 index) { switch (index) { case 0: return 0; // data case 1: return 2; // id + default: GB_PANIC("index > 1"); } } else if (build_context.ptr_size != build_context.int_size) { switch (t->kind) { @@ -1193,6 +1204,7 @@ gb_internal lbValue lb_emit_struct_ep(lbProcedure *p, lbValue s, i32 index) { switch (index) { case 0: result_type = t_rawptr; break; case 1: result_type = t_typeid; break; + default: GB_PANIC("index > 1"); } } else if (is_type_dynamic_array(t)) { switch (index) { @@ -2095,10 +2107,8 @@ gb_internal LLVMValueRef llvm_get_inline_asm(LLVMTypeRef func_type, String const cast(char *)str.text, cast(size_t)str.len, cast(char *)clobbers.text, cast(size_t)clobbers.len, has_side_effects, is_align_stack, - dialect - #if LLVM_VERSION_MAJOR >= 13 - , /*CanThrow*/false - #endif + dialect, + /*CanThrow*/false ); } @@ -2264,12 +2274,12 @@ gb_internal lbValue lb_handle_objc_ivar_get(lbProcedure *p, Ast *expr) { } gb_internal void lb_create_objc_block_helper_procs( - lbModule *m, LLVMTypeRef block_lit_type, isize capture_field_offset, + lbModule *m, LLVMTypeRef block_lit_type, isize capture_field_offset, isize block_id, Slice<lbValue> capture_values, Slice<isize> objc_object_indices, lbProcedure *&out_copy_helper, lbProcedure *&out_dispose_helper ) { - gbString copy_helper_name = gb_string_append_fmt(gb_string_make(temporary_allocator(), ""), "__$objc_block_copy_helper_%lld", m->objc_next_block_id); - gbString dispose_helper_name = gb_string_append_fmt(gb_string_make(temporary_allocator(), ""), "__$objc_block_dispose_helper_%lld", m->objc_next_block_id); + gbString copy_helper_name = gb_string_append_fmt(gb_string_make(temporary_allocator(), ""), "__$%s::objc_block_copy_helper_%lld", m->module_name, block_id); + gbString dispose_helper_name = gb_string_append_fmt(gb_string_make(temporary_allocator(), ""), "__$%s::objc_block_dispose_helper_%lld", m->module_name, block_id); // copy: Block_Literal *dst, Block_Literal *src, i32 field_apropos // dispose: Block_Literal *src, i32 field_apropos @@ -2373,14 +2383,12 @@ gb_internal lbValue lb_handle_objc_block(lbProcedure *p, Ast *expr) { /// https://www.newosxbook.com/src.php?tree=xnu&file=/libkern/libkern/Block_private.h /// https://github.com/llvm/llvm-project/blob/21f1f9558df3830ffa637def364e3c0cb0dbb3c0/compiler-rt/lib/BlocksRuntime/Block_private.h /// https://github.com/apple-oss-distributions/libclosure/blob/3668b0837f47be3cc1c404fb5e360f4ff178ca13/runtime.cpp - ast_node(ce, CallExpr, expr); GB_ASSERT(ce->args.count > 0); lbModule *m = p->module; - m->objc_next_block_id += 1; - + const isize block_id = m->objc_next_block_id++; const isize capture_arg_count = ce->args.count - 1; Type *block_result_type = type_of_expr(expr); @@ -2425,7 +2433,7 @@ gb_internal lbValue lb_handle_objc_block(lbProcedure *p, Ast *expr) { // Create proc with the block signature // (takes a block literal pointer as the first parameter, followed by any expected ones from the user's proc) - gbString block_invoker_name = gb_string_append_fmt(gb_string_make(permanent_allocator(), ""), "__$objc_block_invoker_%lld", m->objc_next_block_id); + gbString block_invoker_name = gb_string_append_fmt(gb_string_make(permanent_allocator(), ""), "__$%s::objc_block_invoker_%lld", m->module_name, block_id); // Add + 1 because the first parameter received is the block literal pointer itself auto invoker_args = array_make<Type *>(temporary_allocator(), block_forward_args + 1, block_forward_args + 1); @@ -2452,14 +2460,16 @@ gb_internal lbValue lb_handle_objc_block(lbProcedure *p, Ast *expr) { lbProcedure *invoker_proc = lb_create_dummy_procedure(m, make_string((u8*)block_invoker_name, gb_string_length(block_invoker_name)), invoker_proc_type); + LLVMSetLinkage(invoker_proc->value, LLVMPrivateLinkage); + lb_add_function_type_attributes(invoker_proc->value, lb_get_function_type(m, invoker_proc_type), ProcCC_CDecl); // Create the block descriptor and block literal - gbString block_lit_type_name = gb_string_make(temporary_allocator(), "__$ObjC_Block_Literal_"); - block_lit_type_name = gb_string_append_fmt(block_lit_type_name, "%lld", m->objc_next_block_id); + gbString block_lit_type_name = gb_string_make(temporary_allocator(), ""); + block_lit_type_name = gb_string_append_fmt(block_lit_type_name, "__$%s::ObjC_Block_Literal_%lld", m->module_name, block_id); - gbString block_desc_type_name = gb_string_make(temporary_allocator(), "__$ObjC_Block_Descriptor_"); - block_desc_type_name = gb_string_append_fmt(block_desc_type_name, "%lld", m->objc_next_block_id); + gbString block_desc_type_name = gb_string_make(temporary_allocator(), ""); + block_desc_type_name = gb_string_append_fmt(block_desc_type_name, "__$%s::ObjC_Block_Descriptor_%lld", m->module_name,block_id); LLVMTypeRef block_lit_type = {}; LLVMTypeRef block_desc_type = {}; @@ -2503,7 +2513,7 @@ gb_internal lbValue lb_handle_objc_block(lbProcedure *p, Ast *expr) { // Generate copy and dispose helper functions for captured params that are Objective-C objects (or a Block) if (has_objc_fields) { - lb_create_objc_block_helper_procs(m, block_lit_type, capture_fields_offset, + lb_create_objc_block_helper_procs(m, block_lit_type, capture_fields_offset, block_id, slice(captured_values, 0, captured_values.count), slice(objc_captures, 0, objc_captures.count), copy_helper, dispose_helper); @@ -2521,8 +2531,8 @@ gb_internal lbValue lb_handle_objc_block(lbProcedure *p, Ast *expr) { } // Create global block descriptor - gbString desc_global_name = gb_string_make(temporary_allocator(), "__$objc_block_desc_"); - desc_global_name = gb_string_append_fmt(desc_global_name, "%lld", m->objc_next_block_id); + gbString desc_global_name = gb_string_make(temporary_allocator(), ""); + desc_global_name = gb_string_append_fmt(desc_global_name, "__$%s::objc_block_desc_%lld", m->module_name, block_id); LLVMValueRef p_descriptor = LLVMAddGlobal(m->mod, block_desc_type, desc_global_name); LLVMSetInitializer(p_descriptor, block_desc_initializer); @@ -2531,45 +2541,66 @@ gb_internal lbValue lb_handle_objc_block(lbProcedure *p, Ast *expr) { /// Invoker body lb_begin_procedure_body(invoker_proc); { - auto call_args = array_make<lbValue>(temporary_allocator(), user_proc.param_count, user_proc.param_count); + // Reserve 2 extra arguments for: Indirect return values and context. + auto call_args = array_make<LLVMValueRef>(temporary_allocator(), 0, user_proc.param_count + 2); - for (isize i = 1; i < invoker_proc->raw_input_parameters.count; i++) { - lbValue arg = {}; - arg.type = invoker_args[i]; - arg.value = invoker_proc->raw_input_parameters[i], - call_args[i-1] = arg; - } + isize block_literal_arg_index = 0; - LLVMValueRef block_literal = invoker_proc->raw_input_parameters[0]; + lbFunctionType* user_proc_ft = lb_get_function_type(m, user_proc_value.type); - // Push context, if needed - if (user_proc.calling_convention == ProcCC_Odin) { - LLVMValueRef p_context = LLVMBuildStructGEP2(invoker_proc->builder, block_lit_type, block_literal, 5, "context"); - lbValue ctx_val = {}; - ctx_val.type = t_context_ptr; - ctx_val.value = p_context; + lbArgKind return_kind = {}; + + GB_ASSERT(user_proc.result_count <= 1); + if (user_proc.result_count > 0) { + return_kind = user_proc_ft->ret.kind; - lb_push_context_onto_stack(invoker_proc, lb_addr(ctx_val)); + if (return_kind == lbArg_Indirect) { + // Forward indirect return value + array_add(&call_args, invoker_proc->raw_input_parameters[0]); + block_literal_arg_index = 1; + } + } + + // Forward raw arguments + for (isize i = block_literal_arg_index+1; i < invoker_proc->raw_input_parameters.count; i++) { + array_add(&call_args, invoker_proc->raw_input_parameters[i]); } + LLVMValueRef block_literal = invoker_proc->raw_input_parameters[block_literal_arg_index]; + // Copy capture parameters from the block literal + isize capture_arg_in_user_proc_start_index = user_proc_ft->args.count - capture_arg_count; + if (user_proc.calling_convention == ProcCC_Odin) { + capture_arg_in_user_proc_start_index -= 1; + } + for (isize i = 0; i < capture_arg_count; i++) { LLVMValueRef cap_value = LLVMBuildStructGEP2(invoker_proc->builder, block_lit_type, block_literal, unsigned(capture_fields_offset + i), ""); - lbValue cap_arg = {}; - cap_arg.value = cap_value; - cap_arg.type = alloc_type_pointer(captured_values[i].type); + // Don't emit load if indirect. Pass the pointer as-is + isize cap_arg_index_in_user_proc = capture_arg_in_user_proc_start_index + i; + + if (user_proc_ft->args[cap_arg_index_in_user_proc].kind != lbArg_Indirect) { + cap_value = OdinLLVMBuildLoad(invoker_proc, lb_type(invoker_proc->module, captured_values[i].type), cap_value); + } - lbValue arg = lb_emit_load(invoker_proc, cap_arg); - call_args[block_forward_args+i] = arg; + array_add(&call_args, cap_value); } - lbValue result = lb_emit_call(invoker_proc, user_proc_value, call_args, proc_lit->ProcLit.inlining); + // Push context, if needed + if (user_proc.calling_convention == ProcCC_Odin) { + LLVMValueRef p_context = LLVMBuildStructGEP2(invoker_proc->builder, block_lit_type, block_literal, 5, "context"); + array_add(&call_args, p_context); + } - GB_ASSERT(user_proc.result_count <= 1); - if (user_proc.result_count > 0) { - GB_ASSERT(result.value != nullptr); - LLVMBuildRet(p->builder, result.value); + LLVMTypeRef fnp = lb_type_internal_for_procedures_raw(m, user_proc_value.type); + LLVMValueRef ret_val = LLVMBuildCall2(invoker_proc->builder, fnp, user_proc_value.value, call_args.data, (unsigned)call_args.count, ""); + + if (user_proc.result_count > 0 && return_kind != lbArg_Indirect) { + LLVMBuildRet(invoker_proc->builder, ret_val); + } + else { + LLVMBuildRetVoid(invoker_proc->builder); } } lb_end_procedure_body(invoker_proc); @@ -2585,10 +2616,10 @@ gb_internal lbValue lb_handle_objc_block(lbProcedure *p, Ast *expr) { } gbString block_var_name = gb_string_make(temporary_allocator(), "__$objc_block_literal_"); - block_var_name = gb_string_append_fmt(block_var_name, "%lld", m->objc_next_block_id); + block_var_name = gb_string_append_fmt(block_var_name, "%lld", block_id); - lbValue result = {}; - result.type = block_result_type; + lbValue block_result = {}; + block_result.type = block_result_type; lbValue isa_val = lb_find_runtime_value(m, is_global ? str_lit("_NSConcreteGlobalBlock") : str_lit("_NSConcreteStackBlock")); lbValue flags_val = lb_const_int(m, t_i32, (u64)raw_flags); @@ -2596,7 +2627,7 @@ gb_internal lbValue lb_handle_objc_block(lbProcedure *p, Ast *expr) { if (is_global) { LLVMValueRef p_block_lit = LLVMAddGlobal(m->mod, block_lit_type, block_var_name); - result.value = p_block_lit; + block_result.value = p_block_lit; LLVMValueRef fields_values[5] = { isa_val.value, // isa @@ -2611,7 +2642,7 @@ gb_internal lbValue lb_handle_objc_block(lbProcedure *p, Ast *expr) { } else { LLVMValueRef p_block_lit = llvm_alloca(p, block_lit_type, lb_alignof(block_lit_type), block_var_name); - result.value = p_block_lit; + block_result.value = p_block_lit; // Initialize it LLVMValueRef f_isa = LLVMBuildStructGEP2(p->builder, block_lit_type, p_block_lit, 0, "isa"); @@ -2651,7 +2682,20 @@ gb_internal lbValue lb_handle_objc_block(lbProcedure *p, Ast *expr) { } } - return result; + return block_result; +} + +gb_internal lbValue lb_handle_objc_block_invoke(lbProcedure *p, Ast *expr) { + return {}; +} + +gb_internal lbValue lb_handle_objc_super(lbProcedure *p, Ast *expr) { + ast_node(ce, CallExpr, expr); + GB_ASSERT(ce->args.count == 1); + + // NOTE(harold): This doesn't actually do anything by itself, + // it has an effect when used on the left side of a selector call expression. + return lb_build_expr(p, ce->args[0]); } gb_internal lbValue lb_handle_objc_find_selector(lbProcedure *p, Ast *expr) { @@ -2767,6 +2811,124 @@ gb_internal lbValue lb_handle_objc_send(lbProcedure *p, Ast *expr) { return lb_emit_call(p, the_proc, args); } +gb_internal lbValue lb_handle_objc_auto_send(lbProcedure *p, Ast *expr, Slice<lbValue> const arg_values) { + ast_node(ce, CallExpr, expr); + + lbModule *m = p->module; + CheckerInfo *info = m->info; + ObjcMsgData data = map_must_get(&info->objc_msgSend_types, expr); + + Type *proc_type = data.proc_type; + GB_ASSERT(proc_type != nullptr); + + Entity *objc_method_ent = entity_of_node(ce->proc); + GB_ASSERT(objc_method_ent != nullptr); + GB_ASSERT(objc_method_ent->kind == Entity_Procedure); + GB_ASSERT(objc_method_ent->Procedure.objc_selector_name.len > 0); + + auto &proc = proc_type->Proc; + GB_ASSERT(proc.param_count >= 2); + + Type *objc_super_orig_type = nullptr; + if (ce->args.count > 0) { + objc_super_orig_type = unparen_expr(ce->args[0])->tav.objc_super_target; + } + + isize arg_offset = 1; + lbValue id = {}; + if (!objc_method_ent->Procedure.is_objc_class_method) { + GB_ASSERT(ce->args.count > 0); + id = arg_values[0]; + + if (objc_super_orig_type) { + GB_ASSERT(objc_super_orig_type->kind == Type_Named); + + auto& tn = objc_super_orig_type->Named.type_name->TypeName; + lbAddr p_supercls = lb_handle_objc_find_or_register_class(p, tn.objc_class_name, tn.objc_is_implementation ? objc_super_orig_type : nullptr); + + lbValue supercls = lb_addr_load(p, p_supercls); + lbAddr p_objc_super = lb_add_local_generated(p, t_objc_super, false); + + lbValue f_id = lb_emit_struct_ep(p, p_objc_super.addr, 0); + lbValue f_superclass = lb_emit_struct_ep(p, p_objc_super.addr, 1); + + id = lb_emit_conv(p, id, t_objc_id); + lb_emit_store(p, f_id, id); + lb_emit_store(p, f_superclass, supercls); + + id = p_objc_super.addr; + } + } else { + Entity *objc_class = objc_method_ent->Procedure.objc_class; + if (ce->proc->kind == Ast_SelectorExpr) { + // NOTE (harold): If called via a selector expression (ex: Foo.alloc()), then we should use + // the lhs-side to determine the class. This allows for class methods to be called + // with the correct class as the target, even when the method is defined in a superclass. + ast_node(se, SelectorExpr, ce->proc); + GB_ASSERT(se->expr->tav.mode == Addressing_Type && se->expr->tav.type->kind == Type_Named); + + objc_class = entity_from_expr(se->expr); + GB_ASSERT(objc_class); + GB_ASSERT(objc_class->kind == Entity_TypeName); + + if (objc_class->TypeName.is_type_alias) { + objc_class = objc_class->type->Named.type_name; + } + + GB_ASSERT(objc_class->TypeName.objc_class_name != ""); + } + + Type *class_impl_type = objc_class->TypeName.objc_is_implementation ? objc_class->type : nullptr; + + id = lb_addr_load(p, lb_handle_objc_find_or_register_class(p, objc_class->TypeName.objc_class_name, class_impl_type)); + arg_offset = 0; + } + + lbValue sel = lb_addr_load(p, lb_handle_objc_find_or_register_selector(p, objc_method_ent->Procedure.objc_selector_name)); + + auto args = array_make<lbValue>(permanent_allocator(), 0, arg_values.count + 2 - arg_offset); + + array_add(&args, id); + array_add(&args, sel); + + for (isize i = arg_offset; i < ce->args.count; i++) { + array_add(&args, arg_values[i]); + } + + lbValue the_proc = {}; + + if (!objc_super_orig_type) { + switch (data.kind) { + default: + GB_PANIC("unhandled ObjcMsgKind %u", data.kind); + break; + case ObjcMsg_normal: the_proc = lb_lookup_runtime_procedure(m, str_lit("objc_msgSend")); break; + case ObjcMsg_fpret: the_proc = lb_lookup_runtime_procedure(m, str_lit("objc_msgSend_fpret")); break; + case ObjcMsg_fp2ret: the_proc = lb_lookup_runtime_procedure(m, str_lit("objc_msgSend_fp2ret")); break; + case ObjcMsg_stret: the_proc = lb_lookup_runtime_procedure(m, str_lit("objc_msgSend_stret")); break; + } + } else { + switch (data.kind) { + default: + GB_PANIC("unhandled ObjcMsgKind %u", data.kind); + break; + case ObjcMsg_normal: + case ObjcMsg_fpret: + case ObjcMsg_fp2ret: + the_proc = lb_lookup_runtime_procedure(m, str_lit("objc_msgSendSuper2")); + break; + case ObjcMsg_stret: + the_proc = lb_lookup_runtime_procedure(m, str_lit("objc_msgSendSuper2_stret")); + break; + } + } + + the_proc = lb_emit_conv(p, the_proc, data.proc_type); + + return lb_emit_call(p, the_proc, args); +} + + gb_internal LLVMAtomicOrdering llvm_atomic_ordering_from_odin(ExactValue const &value) { GB_ASSERT(value.kind == ExactValue_Integer); i64 v = exact_value_to_i64(value); @@ -2787,3 +2949,292 @@ gb_internal LLVMAtomicOrdering llvm_atomic_ordering_from_odin(Ast *expr) { ExactValue value = type_and_value_of_expr(expr).value; return llvm_atomic_ordering_from_odin(value); } + + + +struct lbDiagParaPolyEntry { + Entity *entity; + String canonical_name; + isize count; + isize total_code_size; +}; + +gb_internal isize lb_total_code_size(lbProcedure *p) { + isize instruction_count = 0; + + LLVMBasicBlockRef first = LLVMGetFirstBasicBlock(p->value); + + for (LLVMBasicBlockRef block = first; block != nullptr; block = LLVMGetNextBasicBlock(block)) { + for (LLVMValueRef instr = LLVMGetFirstInstruction(block); instr != nullptr; instr = LLVMGetNextInstruction(instr)) { + instruction_count += 1; + } + } + return instruction_count; + +} + +gb_internal void lb_do_para_poly_diagnostics(lbGenerator *gen) { + PtrMap<Entity * /* Parent */, lbDiagParaPolyEntry> procs = {}; + map_init(&procs); + defer (map_destroy(&procs)); + + for (auto &entry : gen->modules) { + lbModule *m = entry.value; + for (lbProcedure *p : m->generated_procedures) { + Entity *e = p->entity; + if (e == nullptr) { + continue; + } + if (p->builder == nullptr) { + continue; + } + + DeclInfo *d = e->decl_info; + Entity *para_poly_parent = d->para_poly_original; + if (para_poly_parent == nullptr) { + continue; + } + + lbDiagParaPolyEntry *entry = map_get(&procs, para_poly_parent); + if (entry == nullptr) { + lbDiagParaPolyEntry entry = {}; + entry.entity = para_poly_parent; + entry.count = 0; + + + gbString w = string_canonical_entity_name(permanent_allocator(), entry.entity); + String name = make_string_c(w); + + for (isize i = 0; i < name.len; i++) { + String s = substring(name, i, name.len); + if (string_starts_with(s, str_lit(":proc"))) { + name = substring(name, 0, i); + break; + } + } + + entry.canonical_name = name; + + map_set(&procs, para_poly_parent, entry); + } + entry = map_get(&procs, para_poly_parent); + GB_ASSERT(entry != nullptr); + entry->count += 1; + entry->total_code_size += lb_total_code_size(p); + } + } + + + auto entries = array_make<lbDiagParaPolyEntry>(heap_allocator(), 0, procs.count); + defer (array_free(&entries)); + + for (auto &entry : procs) { + array_add(&entries, entry.value); + } + + array_sort(entries, [](void const *a, void const *b) -> int { + lbDiagParaPolyEntry *x = cast(lbDiagParaPolyEntry *)a; + lbDiagParaPolyEntry *y = cast(lbDiagParaPolyEntry *)b; + if (x->total_code_size > y->total_code_size) { + return -1; + } + if (x->total_code_size < y->total_code_size) { + return +1; + } + return string_compare(x->canonical_name, y->canonical_name); + }); + + + gb_printf("Parametric Polymorphic Procedure Diagnostics\n"); + gb_printf("------------------------------------------------------------------------------------------\n"); + + gb_printf("Sorted by Total Instruction Count Descending (Top 100)\n\n"); + gb_printf("Total Instruction Count | Instantiation Count | Average Instruction Count | Procedure Name\n"); + + isize max_count = 100; + for (auto &entry : entries) { + isize code_size = entry.total_code_size; + isize count = entry.count; + String name = entry.canonical_name; + + f64 average = cast(f64)code_size / cast(f64)gb_max(count, 1); + + gb_printf("%23td | %19td | %25.2f | %.*s\n", code_size, count, average, LIT(name)); + if (max_count-- <= 0) { + break; + } + } + + gb_printf("------------------------------------------------------------------------------------------\n"); + + array_sort(entries, [](void const *a, void const *b) -> int { + lbDiagParaPolyEntry *x = cast(lbDiagParaPolyEntry *)a; + lbDiagParaPolyEntry *y = cast(lbDiagParaPolyEntry *)b; + if (x->count > y->count) { + return -1; + } + if (x->count < y->count) { + return +1; + } + + return string_compare(x->canonical_name, y->canonical_name); + }); + + gb_printf("Sorted by Total Instantiation Count Descending (Top 100)\n\n"); + gb_printf("Instantiation Count | Total Instruction Count | Average Instruction Count | Procedure Name\n"); + + max_count = 100; + for (auto &entry : entries) { + isize code_size = entry.total_code_size; + isize count = entry.count; + String name = entry.canonical_name; + + + f64 average = cast(f64)code_size / cast(f64)gb_max(count, 1); + + gb_printf("%19td | %23td | %25.2f | %.*s\n", count, code_size, average, LIT(name)); + if (max_count-- <= 0) { + break; + } + } + + gb_printf("------------------------------------------------------------------------------------------\n"); + + + array_sort(entries, [](void const *a, void const *b) -> int { + lbDiagParaPolyEntry *x = cast(lbDiagParaPolyEntry *)a; + lbDiagParaPolyEntry *y = cast(lbDiagParaPolyEntry *)b; + if (x->count < y->count) { + return -1; + } + if (x->count > y->count) { + return +1; + } + + if (x->total_code_size > y->total_code_size) { + return -1; + } + if (x->total_code_size < y->total_code_size) { + return +1; + } + + return string_compare(x->canonical_name, y->canonical_name); + }); + + gb_printf("Single Instanced Parametric Polymorphic Procedures\n\n"); + gb_printf("Instruction Count | Procedure Name\n"); + for (auto &entry : entries) { + isize code_size = entry.total_code_size; + isize count = entry.count; + String name = entry.canonical_name; + if (count != 1) { + break; + } + + gb_printf("%17td | %.*s\n", code_size, LIT(name)); + } + +} + +struct lbDiagModuleEntry { + lbModule *m; + String name; + isize global_internal_count; + isize global_external_count; + isize proc_internal_count; + isize proc_external_count; + isize total_instruction_count; +}; + +gb_internal void lb_do_module_diagnostics(lbGenerator *gen) { + Array<lbDiagModuleEntry> modules = {}; + array_init(&modules, heap_allocator()); + defer (array_free(&modules)); + + for (auto &em : gen->modules) { + lbModule *m = em.value; + + { + lbDiagModuleEntry entry = {}; + entry.m = m; + entry.name = make_string_c(m->module_name); + array_add(&modules, entry); + } + lbDiagModuleEntry &entry = modules[modules.count-1]; + + for (LLVMValueRef p = LLVMGetFirstFunction(m->mod); p != nullptr; p = LLVMGetNextFunction(p)) { + LLVMBasicBlockRef block = LLVMGetFirstBasicBlock(p); + if (block == nullptr) { + entry.proc_external_count += 1; + } else { + entry.proc_internal_count += 1; + + for (; block != nullptr; block = LLVMGetNextBasicBlock(block)) { + for (LLVMValueRef i = LLVMGetFirstInstruction(block); i != nullptr; i = LLVMGetNextInstruction(i)) { + entry.total_instruction_count += 1; + } + } + } + } + + for (LLVMValueRef g = LLVMGetFirstGlobal(m->mod); g != nullptr; g = LLVMGetNextGlobal(g)) { + LLVMLinkage linkage = LLVMGetLinkage(g); + if (linkage == LLVMExternalLinkage) { + entry.global_external_count += 1; + } else { + entry.global_internal_count += 1; + } + } + } + + array_sort(modules, [](void const *a, void const *b) -> int { + lbDiagModuleEntry *x = cast(lbDiagModuleEntry *)a; + lbDiagModuleEntry *y = cast(lbDiagModuleEntry *)b; + + if (x->total_instruction_count > y->total_instruction_count) { + return -1; + } + if (x->total_instruction_count < y->total_instruction_count) { + return +1; + } + + return string_compare(x->name, y->name); + }); + + gb_printf("Module Diagnostics\n\n"); + gb_printf("Total Instructions | Global Internals | Global Externals | Proc Internals | Proc Externals | Files | Instructions/File | Instructions/Proc | Module Name\n"); + gb_printf("-------------------+------------------+------------------+----------------+----------------+-------+-------------------+-------------------+------------\n"); + for (auto &entry : modules) { + isize file_count = 1; + if (entry.m->file != nullptr) { + file_count = 1; + } else if (entry.m->pkg) { + file_count = entry.m->pkg->files.count; + } + + f64 instructions_per_file = cast(f64)entry.total_instruction_count / gb_max(1.0, cast(f64)file_count); + f64 instructions_per_proc = cast(f64)entry.total_instruction_count / gb_max(1.0, cast(f64)entry.proc_internal_count); + + gb_printf("%18td | %16td | %16td | %14td | %14td | %5td | %17.1f | %17.1f | %s \n", + entry.total_instruction_count, + entry.global_internal_count, + entry.global_external_count, + entry.proc_internal_count, + entry.proc_external_count, + file_count, + instructions_per_file, + instructions_per_proc, + entry.m->module_name); + } + + +} + +gb_internal void lb_do_build_diagnostics(lbGenerator *gen) { + lb_do_para_poly_diagnostics(gen); + gb_printf("------------------------------------------------------------------------------------------\n"); + gb_printf("------------------------------------------------------------------------------------------\n\n"); + lb_do_module_diagnostics(gen); + gb_printf("------------------------------------------------------------------------------------------\n"); + gb_printf("------------------------------------------------------------------------------------------\n\n"); +} diff --git a/src/main.cpp b/src/main.cpp index db4dee080..9a5df8aea 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -334,6 +334,7 @@ enum BuildFlagKind { BuildFlag_ShowDefineables, BuildFlag_ExportDefineables, + BuildFlag_IgnoreUnusedDefineables, BuildFlag_Vet, BuildFlag_VetShadowing, @@ -391,9 +392,12 @@ enum BuildFlagKind { BuildFlag_MinLinkLibs, BuildFlag_PrintLinkerFlags, + BuildFlag_ExportLinkedLibraries, BuildFlag_IntegerDivisionByZero, + BuildFlag_BuildDiagnostics, + // internal use only BuildFlag_InternalFastISel, BuildFlag_InternalIgnoreLazy, @@ -403,6 +407,8 @@ enum BuildFlagKind { BuildFlag_InternalCached, BuildFlag_InternalNoInline, BuildFlag_InternalByValue, + BuildFlag_InternalWeakMonomorphization, + BuildFlag_InternalLLVMVerification, BuildFlag_Tilde, @@ -558,6 +564,7 @@ gb_internal bool parse_build_flags(Array<String> args) { add_flag(&build_flags, BuildFlag_ShowDefineables, str_lit("show-defineables"), BuildFlagParam_None, Command__does_check); add_flag(&build_flags, BuildFlag_ExportDefineables, str_lit("export-defineables"), BuildFlagParam_String, Command__does_check); + add_flag(&build_flags, BuildFlag_IgnoreUnusedDefineables, str_lit("ignore-unused-defineables"), BuildFlagParam_None, Command__does_check); add_flag(&build_flags, BuildFlag_Vet, str_lit("vet"), BuildFlagParam_None, Command__does_check); add_flag(&build_flags, BuildFlag_VetUnused, str_lit("vet-unused"), BuildFlagParam_None, Command__does_check); @@ -612,11 +619,13 @@ gb_internal bool parse_build_flags(Array<String> args) { add_flag(&build_flags, BuildFlag_MaxErrorCount, str_lit("max-error-count"), BuildFlagParam_Integer, Command_all); add_flag(&build_flags, BuildFlag_MinLinkLibs, str_lit("min-link-libs"), BuildFlagParam_None, Command__does_build); + add_flag(&build_flags, BuildFlag_ExportLinkedLibraries, str_lit("export-linked-libs-file"), BuildFlagParam_String, Command__does_check); add_flag(&build_flags, BuildFlag_PrintLinkerFlags, str_lit("print-linker-flags"), BuildFlagParam_None, Command_build); add_flag(&build_flags, BuildFlag_IntegerDivisionByZero, str_lit("integer-division-by-zero"), BuildFlagParam_String, Command__does_check); + add_flag(&build_flags, BuildFlag_BuildDiagnostics, str_lit("build-diagnostics"), BuildFlagParam_None, Command__does_build); add_flag(&build_flags, BuildFlag_InternalFastISel, str_lit("internal-fast-isel"), BuildFlagParam_None, Command_all); add_flag(&build_flags, BuildFlag_InternalIgnoreLazy, str_lit("internal-ignore-lazy"), BuildFlagParam_None, Command_all); @@ -626,6 +635,8 @@ gb_internal bool parse_build_flags(Array<String> args) { add_flag(&build_flags, BuildFlag_InternalCached, str_lit("internal-cached"), BuildFlagParam_None, Command_all); add_flag(&build_flags, BuildFlag_InternalNoInline, str_lit("internal-no-inline"), BuildFlagParam_None, Command_all); add_flag(&build_flags, BuildFlag_InternalByValue, str_lit("internal-by-value"), BuildFlagParam_None, Command_all); + add_flag(&build_flags, BuildFlag_InternalWeakMonomorphization, str_lit("internal-weak-monomorphization"), BuildFlagParam_None, Command_all); + add_flag(&build_flags, BuildFlag_InternalLLVMVerification, str_lit("internal-ignore-llvm-verification"), BuildFlagParam_None, Command_all); #if ALLOW_TILDE add_flag(&build_flags, BuildFlag_Tilde, str_lit("tilde"), BuildFlagParam_None, Command__does_build); @@ -936,6 +947,11 @@ gb_internal bool parse_build_flags(Array<String> args) { break; } + case BuildFlag_IgnoreUnusedDefineables: { + GB_ASSERT(value.kind == ExactValue_Invalid); + build_context.ignore_unused_defineables = true; + break; + } case BuildFlag_ShowSystemCalls: { GB_ASSERT(value.kind == ExactValue_Invalid); build_context.show_system_calls = true; @@ -1293,23 +1309,17 @@ gb_internal bool parse_build_flags(Array<String> args) { build_context.vet_flags |= VetFlag_All; break; - case BuildFlag_VetUnusedVariables: build_context.vet_flags |= VetFlag_UnusedVariables; break; - case BuildFlag_VetUnusedImports: build_context.vet_flags |= VetFlag_UnusedImports; break; - case BuildFlag_VetUnused: build_context.vet_flags |= VetFlag_Unused; break; - case BuildFlag_VetShadowing: build_context.vet_flags |= VetFlag_Shadowing; break; - case BuildFlag_VetUsingStmt: build_context.vet_flags |= VetFlag_UsingStmt; break; - case BuildFlag_VetUsingParam: build_context.vet_flags |= VetFlag_UsingParam; break; - case BuildFlag_VetStyle: build_context.vet_flags |= VetFlag_Style; break; - case BuildFlag_VetSemicolon: build_context.vet_flags |= VetFlag_Semicolon; break; - case BuildFlag_VetCast: build_context.vet_flags |= VetFlag_Cast; break; - case BuildFlag_VetTabs: build_context.vet_flags |= VetFlag_Tabs; break; - case BuildFlag_VetUnusedProcedures: - build_context.vet_flags |= VetFlag_UnusedProcedures; - if (!set_flags[BuildFlag_VetPackages]) { - gb_printf_err("-%.*s must be used with -vet-packages\n", LIT(name)); - bad_flags = true; - } - break; + case BuildFlag_VetUnusedVariables: build_context.vet_flags |= VetFlag_UnusedVariables; break; + case BuildFlag_VetUnusedImports: build_context.vet_flags |= VetFlag_UnusedImports; break; + case BuildFlag_VetUnused: build_context.vet_flags |= VetFlag_Unused; break; + case BuildFlag_VetShadowing: build_context.vet_flags |= VetFlag_Shadowing; break; + case BuildFlag_VetUsingStmt: build_context.vet_flags |= VetFlag_UsingStmt; break; + case BuildFlag_VetUsingParam: build_context.vet_flags |= VetFlag_UsingParam; break; + case BuildFlag_VetStyle: build_context.vet_flags |= VetFlag_Style; break; + case BuildFlag_VetSemicolon: build_context.vet_flags |= VetFlag_Semicolon; break; + case BuildFlag_VetCast: build_context.vet_flags |= VetFlag_Cast; break; + case BuildFlag_VetTabs: build_context.vet_flags |= VetFlag_Tabs; break; + case BuildFlag_VetUnusedProcedures: build_context.vet_flags |= VetFlag_UnusedProcedures; break; case BuildFlag_VetPackages: { @@ -1540,6 +1550,14 @@ gb_internal bool parse_build_flags(Array<String> args) { build_context.min_link_libs = true; break; + case BuildFlag_ExportLinkedLibraries: + build_context.export_linked_libs_path = string_trim_whitespace(value.value_string); + if (build_context.export_linked_libs_path.len == 0) { + gb_printf_err("-%.*s specified an empty path\n", LIT(name)); + bad_flags = true; + } + break; + case BuildFlag_PrintLinkerFlags: build_context.print_linker_flags = true; break; @@ -1552,12 +1570,18 @@ gb_internal bool parse_build_flags(Array<String> args) { build_context.integer_division_by_zero_behaviour = IntegerDivisionByZero_Zero; } else if (str_eq_ignore_case(value.value_string, "self")) { build_context.integer_division_by_zero_behaviour = IntegerDivisionByZero_Self; - }else { - gb_printf_err("-integer-division-by-zero options are 'trap', 'zero', and 'self'.\n"); + } else if (str_eq_ignore_case(value.value_string, "all-bits")) { + build_context.integer_division_by_zero_behaviour = IntegerDivisionByZero_AllBits; + } else { + gb_printf_err("-integer-division-by-zero options are 'trap', 'zero', 'self', and 'all-bits'.\n"); bad_flags = true; } break; + case BuildFlag_BuildDiagnostics: + build_context.build_diagnostics = true; + break; + case BuildFlag_InternalFastISel: build_context.fast_isel = true; break; @@ -1584,6 +1608,13 @@ gb_internal bool parse_build_flags(Array<String> args) { case BuildFlag_InternalByValue: build_context.internal_by_value = true; break; + case BuildFlag_InternalWeakMonomorphization: + build_context.internal_weak_monomorphization = true; + break; + case BuildFlag_InternalLLVMVerification: + build_context.internal_ignore_llvm_verification = true; + break; + case BuildFlag_Tilde: build_context.tilde_backend = true; @@ -1753,6 +1784,11 @@ gb_internal bool parse_build_flags(Array<String> args) { } } + if (set_flags[BuildFlag_VetUnusedProcedures] && !set_flags[BuildFlag_VetPackages]) { + gb_printf_err("-vet-unused-procedures must be used with -vet-packages\n"); + bad_flags = true; + } + if ((!(build_context.export_timings_format == TimingsExportUnspecified)) && (build_context.export_timings_file.len == 0)) { gb_printf_err("`-export-timings:<format>` requires `-export-timings-file:<filename>` to be specified as well\n"); bad_flags = true; @@ -2244,6 +2280,63 @@ gb_internal void export_dependencies(Checker *c) { } } +gb_internal void export_linked_libraries(LinkerData *gen) { + gbFile f = {}; + char * fileName = (char *)build_context.export_linked_libs_path.text; + gbFileError err = gb_file_open_mode(&f, gbFileMode_Write, fileName); + if (err != gbFileError_None) { + gb_printf_err("Failed to export linked library list to: %s\n", fileName); + exit_with_errors(); + return; + } + defer (gb_file_close(&f)); + + StringSet min_libs_set = {}; + string_set_init(&min_libs_set, 64); + defer (string_set_destroy(&min_libs_set)); + + for (auto *e : gen->foreign_libraries) { + GB_ASSERT(e->kind == Entity_LibraryName); + ast_node(imp, ForeignImportDecl, e->LibraryName.decl); + + for (isize i = 0; i < e->LibraryName.paths.count; i++) { + String lib_path = string_trim_whitespace(e->LibraryName.paths[i]); + if (lib_path.len == 0) { + continue; + } + + if (string_set_update(&min_libs_set, lib_path)) { + continue; + } + + gb_fprintf(&f, "%.*s\t", LIT(lib_path)); + + String ext = path_extension(lib_path, false); + if (str_eq_ignore_case(ext, "a") || str_eq_ignore_case(ext, "lib") || + str_eq_ignore_case(ext, "o") || str_eq_ignore_case(ext, "obj") + ) { + gb_fprintf(&f, "static"); + } else { + gb_fprintf(&f, "dynamic"); + } + + gb_fprintf(&f, "\t"); + + Ast *file_path = imp->filepaths[i]; + GB_ASSERT(file_path->tav.mode == Addressing_Constant && file_path->tav.value.kind == ExactValue_String); + String file_path_str = file_path->tav.value.value_string; + + if (string_starts_with(file_path_str, str_lit("system:"))) { + gb_fprintf(&f, "system"); + } else { + gb_fprintf(&f, "user"); + } + + gb_fprintf(&f, "\n"); + } + } +} + gb_internal void remove_temp_files(lbGenerator *gen) { if (build_context.keep_temp_files) return; @@ -2797,6 +2890,10 @@ gb_internal int print_show_help(String const arg0, String command, String option print_usage_line(2, "Shows an overview of all the #config/#defined usages in the project."); } + if (print_flag("-ignore-unused-defineables")) { + print_usage_line(2, "Silence warning/error if a -define doesn't have at least one #config/#defined usage."); + } + if (print_flag("-show-system-calls")) { print_usage_line(2, "Prints the whole command and arguments for calls to external tools like linker and assembler."); } @@ -2826,7 +2923,7 @@ gb_internal int print_show_help(String const arg0, String command, String option print_usage_line(2, "Errs on unneeded tokens, such as unneeded semicolons."); print_usage_line(2, "Errs on missing trailing commas followed by a newline."); print_usage_line(2, "Errs on deprecated syntax."); - print_usage_line(2, "Errs when the attached-brace style in not adhered to (also known as 1TBS)."); + print_usage_line(2, "Errs when the attached-brace style is not adhered to (also known as 1TBS)."); print_usage_line(2, "Errs when 'case' labels are not in the same column as the associated 'switch' token."); } } @@ -3050,7 +3147,8 @@ gb_internal void print_show_unused(Checker *c) { if (e->token.string == "_") { continue; } - if (ptr_set_exists(&info->minimum_dependency_set, e)) { + + if (e->min_dep_count.load(std::memory_order_relaxed) > 0) { continue; } array_add(&unused, e); @@ -3617,6 +3715,11 @@ int main(int arg_count, char const **arg_ptr) { // print_usage_line(0, "%.*s 32-bit is not yet supported for this platform", LIT(args[0])); // return 1; // } + + // Warn about Windows i386 thread-local storage limitations + if (build_context.metrics.arch == TargetArch_i386 && build_context.metrics.os == TargetOs_windows) { + gb_printf_err("Warning: Thread-local storage is disabled on Windows i386.\n"); + } // Check chosen microarchitecture. If not found or ?, print list. bool print_microarch_list = true; @@ -3695,6 +3798,11 @@ int main(int arg_count, char const **arg_ptr) { String item = string_split_iterator(&target_it, ','); if (item == "") break; + if (*item.text == '+' || *item.text == '-') { + item.text++; + item.len--; + } + String invalid; if (!check_target_feature_is_valid_for_target_arch(item, &invalid) && item != str_lit("help")) { if (item != str_lit("?")) { @@ -3744,6 +3852,7 @@ int main(int arg_count, char const **arg_ptr) { if (build_context.show_debug_messages) { debugf("Selected microarch: %.*s\n", LIT(march)); debugf("Default microarch features: %.*s\n", LIT(default_features)); + debugf("Target triplet: %.*s\n", LIT(build_context.metrics.target_triplet)); for_array(i, build_context.build_paths) { String build_path = path_to_string(heap_allocator(), build_context.build_paths[i]); debugf("build_paths[%ld]: %.*s\n", i, LIT(build_path)); @@ -3794,7 +3903,9 @@ int main(int arg_count, char const **arg_ptr) { MAIN_TIME_SECTION("type check"); check_parsed_files(checker); - check_defines(&build_context, checker); + if (!build_context.ignore_unused_defineables) { + check_defines(&build_context, checker); + } if (any_errors()) { print_all_errors(); return 1; @@ -3911,6 +4022,10 @@ int main(int arg_count, char const **arg_ptr) { export_dependencies(checker); } return result; + } else { + if (build_context.export_linked_libs_path != "") { + export_linked_libraries(gen); + } } break; } diff --git a/src/name_canonicalization.cpp b/src/name_canonicalization.cpp index 6a4538e26..f1dccb182 100644 --- a/src/name_canonicalization.cpp +++ b/src/name_canonicalization.cpp @@ -57,10 +57,13 @@ gb_internal isize type_set__find(TypeSet *s, TypeInfoPair pair) { usize mask = s->capacity-1; usize hash_index = cast(usize)hash & mask; for (usize i = 0; i < s->capacity; i++) { - Type *key = s->keys[hash_index].type; - if (are_types_identical_unique_tuples(key, pair.type)) { + auto *e = &s->keys[hash_index]; + u64 hash = e->hash; + Type *key = e->type; + if (hash == pair.hash && + are_types_identical_unique_tuples(key, pair.type)) { return hash_index; - } else if (key == 0) { + } else if (key == nullptr) { return -1; } hash_index = (hash_index+1)&mask; @@ -164,6 +167,48 @@ gb_internal bool type_set_update(TypeSet *s, Type *ptr) { // returns true if it return type_set_update(s, pair); } +gb_internal bool type_set_update_with_mutex(TypeSet *s, TypeInfoPair pair, RWSpinLock *m) { // returns true if it previously existsed + rwlock_acquire_upgrade(m); + if (type_set_exists(s, pair)) { + rwlock_release_upgrade(m); + return true; + } + + rwlock_release_upgrade_and_acquire_write(m); + defer (rwlock_release_write(m)); + + if (s->keys == nullptr) { + type_set_init(s); + } else if (type_set__full(s)) { + type_set_grow(s); + } + GB_ASSERT(s->count < s->capacity); + GB_ASSERT(s->capacity >= 0); + + usize mask = s->capacity-1; + usize hash = cast(usize)pair.hash; + usize hash_index = (cast(usize)hash) & mask; + GB_ASSERT(hash_index < s->capacity); + for (usize i = 0; i < s->capacity; i++) { + TypeInfoPair *key = &s->keys[hash_index]; + GB_ASSERT(!are_types_identical_unique_tuples(key->type, pair.type)); + if (key->hash == TYPE_SET_TOMBSTONE || key->hash == 0) { + *key = pair; + s->count++; + return false; + } + hash_index = (hash_index+1)&mask; + } + + GB_PANIC("ptr set out of memory"); + return false; +} + +gb_internal bool type_set_update_with_mutex(TypeSet *s, Type *ptr, RWSpinLock *m) { // returns true if it previously existsed + TypeInfoPair pair = {ptr, type_hash_canonical_type(ptr)}; + return type_set_update_with_mutex(s, pair, m); +} + gb_internal Type *type_set_add(TypeSet *s, Type *ptr) { type_set_update(s, ptr); @@ -197,9 +242,146 @@ gb_internal gb_inline void type_set_clear(TypeSet *s) { typedef TYPE_WRITER_PROC(TypeWriterProc); +enum { SIP_BLOCK_SIZE = 8 }; + +struct SipHashContext { + u64 v0, v1, v2, v3; // State values + u64 k0, k1; // Split key + isize c_rounds; // Number of message rounds + isize d_rounds; // Number of finalization rounds + u8 buf[SIP_BLOCK_SIZE]; // Provided data + isize last_block; // offset from last block + isize total_length; + bool is_initialized; +}; + +struct TypeidHashContext { + SipHashContext sip; +}; + + +void typeid_hash_context_init(TypeidHashContext *hash_ctx) { + SipHashContext *sip = &hash_ctx->sip; + sip->c_rounds = 2; + sip->d_rounds = 4; + + // some random numbers to act as the seed + sip->k0 = 0xa6592ea25e04ac3cull; + sip->k1 = 0xba3cba04ed28a9aeull; + + // + sip->v0 = 0x736f6d6570736575 ^ sip->k0; + sip->v1 = 0x646f72616e646f6d ^ sip->k1; + sip->v2 = 0x6c7967656e657261 ^ sip->k0; + sip->v3 = 0x7465646279746573 ^ sip->k1; + + sip->last_block = 0; + sip->total_length = 0; + + sip->is_initialized = true; +} + +u64 rotate_left64(u64 x, u64 k) { + static u64 const n = 64; + u64 s = k & (n-1); + return (x<<s) | (x>>(n-2)); +} + +void sip_compress(SipHashContext *sip) { + sip->v0 += sip->v1; + sip->v1 = rotate_left64(sip->v1, 13); + sip->v1 ^= sip->v0; + sip->v0 = rotate_left64(sip->v0, 32); + sip->v2 += sip->v3; + sip->v3 = rotate_left64(sip->v3, 16); + sip->v3 ^= sip->v2; + sip->v0 += sip->v3; + sip->v3 = rotate_left64(sip->v3, 21); + sip->v3 ^= sip->v0; + sip->v2 += sip->v1; + sip->v1 = rotate_left64(sip->v1, 17); + sip->v1 ^= sip->v2; + sip->v2 = rotate_left64(sip->v2, 32); +} + +void sip_block(SipHashContext *sip, void const *ptr, isize len) { + u8 const *data = cast(u8 const *)ptr; + while (len >= SIP_BLOCK_SIZE) { + u64 m = 0; + gb_memcopy(&m, data, 8); + + sip->v3 ^= m; + + for (isize i = 0; i < sip->c_rounds; i++) { + sip_compress(sip); + } + + sip->v0 ^= m; + + data += SIP_BLOCK_SIZE; + len -= SIP_BLOCK_SIZE; + } +} + +void typeid_hash_context_update(TypeidHashContext *ctx, void const *ptr, isize len) { + GB_ASSERT(ctx->sip.is_initialized); + SipHashContext *sip = &ctx->sip; + + u8 const *data = cast(u8 const *)ptr; + sip->total_length += len; + if (sip->last_block > 0) { + isize n = gb_min(SIP_BLOCK_SIZE - sip->last_block, len); + gb_memcopy(sip->buf + sip->last_block, data, n); + sip->last_block += n; + if (sip->last_block == SIP_BLOCK_SIZE) { + sip_block(sip, sip->buf, SIP_BLOCK_SIZE); + sip->last_block = 0; + } + data += n; + len -= n; + } + + if (len >= SIP_BLOCK_SIZE) { + isize n = len & ~(SIP_BLOCK_SIZE-1); + sip_block(sip, data, n); + data += n; + len -= n; + } + if (len > 0) { + isize n = gb_min(SIP_BLOCK_SIZE, len); + gb_memcopy(sip->buf, data, n); + sip->last_block = n; + } +} + +u64 typeid_hash_context_fini(TypeidHashContext *ctx) { + GB_ASSERT(ctx->sip.is_initialized); + SipHashContext *sip = &ctx->sip; + + u8 tmp[SIP_BLOCK_SIZE] = {}; + gb_memcopy(tmp, sip->buf, gb_min(sip->last_block, SIP_BLOCK_SIZE)); + tmp[7] = u8(sip->total_length & 0xff); + sip_block(sip, tmp, SIP_BLOCK_SIZE); + + sip->v2 ^= 0xff; + + for (isize i = 0; i < sip->d_rounds; i++) { + sip_compress(sip); + } + + u64 res = sip->v0 ^ sip->v1 ^ sip->v2 ^ sip->v3; + + *sip = {}; + + return res ? res : 1; +} + + + struct TypeWriter { - TypeWriterProc *proc; - void *user_data; + TypeWriterProc * proc; + void * user_data; + TypeidHashContext hash_ctx; }; bool type_writer_append(TypeWriter *w, void const *ptr, isize len) { @@ -244,13 +426,14 @@ void type_writer_destroy_string(TypeWriter *w) { TYPE_WRITER_PROC(type_writer_hasher_writer_proc) { - u64 *seed = cast(u64 *)w->user_data; - *seed = fnv64a(ptr, len, *seed); + TypeidHashContext *ctx = cast(TypeidHashContext *)w->user_data; + typeid_hash_context_update(ctx, ptr, len); return true; } -void type_writer_make_hasher(TypeWriter *w, u64 *hash) { - w->user_data = hash; +void type_writer_make_hasher(TypeWriter *w, TypeidHashContext *ctx) { + typeid_hash_context_init(ctx); + w->user_data = ctx; w->proc = type_writer_hasher_writer_proc; } @@ -328,12 +511,19 @@ gb_internal u64 type_hash_canonical_type(Type *type) { if (type == nullptr) { return 0; } - u64 hash = fnv64a(nullptr, 0); + u64 prev_hash = type->canonical_hash.load(std::memory_order_relaxed); + if (prev_hash != 0) { + return prev_hash; + } + TypeWriter w = {}; - type_writer_make_hasher(&w, &hash); + type_writer_make_hasher(&w, &w.hash_ctx); write_type_to_canonical_string(&w, type); + u64 hash = typeid_hash_context_fini(&w.hash_ctx); + + type->canonical_hash.store(hash, std::memory_order_relaxed); - return hash ? hash : 1; + return hash; } gb_internal String type_to_canonical_string(gbAllocator allocator, Type *type) { @@ -364,7 +554,7 @@ gb_internal gbString string_canonical_entity_name(gbAllocator allocator, Entity gb_internal void write_canonical_parent_prefix(TypeWriter *w, Entity *e) { GB_ASSERT(e != nullptr); - if (e->kind == Entity_Procedure || e->kind == Entity_TypeName) { + if (e->kind == Entity_Procedure || e->kind == Entity_TypeName || e->kind == Entity_Variable) { if (e->kind == Entity_Procedure && (e->Procedure.is_export || e->Procedure.is_foreign)) { // no prefix return; @@ -474,6 +664,11 @@ gb_internal void write_canonical_entity_name(TypeWriter *w, Entity *e) { } else if (s->flags & (ScopeFlag_Builtin)) { goto write_base_name; } + + if (e->kind == Entity_TypeName) { + goto write_base_name; + } + gb_printf_err("%s WEIRD ENTITY TYPE %s %u %p\n", token_pos_to_string(e->token.pos), type_to_string(e->type), s->flags, s->decl_info); auto const print_scope_flags = [](Scope *s) { @@ -490,7 +685,7 @@ gb_internal void write_canonical_entity_name(TypeWriter *w, Entity *e) { }; print_scope_flags(s); - GB_PANIC("weird entity %.*s", LIT(e->token.string)); + GB_PANIC("weird entity %.*s (%.*s)", LIT(e->token.string), LIT(entity_strings[e->kind])); } if (e->pkg != nullptr) { type_writer_append(w, e->pkg->name.text, e->pkg->name.len); @@ -691,8 +886,9 @@ gb_internal void write_type_to_canonical_string(TypeWriter *w, Type *type) { write_canonical_params(w, type->Struct.polymorphic_params); } - if (type->Struct.is_packed) type_writer_appendc(w, "#packed"); - if (type->Struct.is_raw_union) type_writer_appendc(w, "#raw_union"); + if (type->Struct.is_packed) type_writer_appendc(w, "#packed"); + if (type->Struct.is_raw_union) type_writer_appendc(w, "#raw_union"); + if (type->Struct.is_all_or_none) type_writer_appendc(w, "#all_or_none"); if (type->Struct.custom_min_field_align != 0) type_writer_append_fmt(w, "#min_field_align(%lld)", cast(long long)type->Struct.custom_min_field_align); if (type->Struct.custom_max_field_align != 0) type_writer_append_fmt(w, "#max_field_align(%lld)", cast(long long)type->Struct.custom_max_field_align); if (type->Struct.custom_align != 0) type_writer_append_fmt(w, "#align(%lld)", cast(long long)type->Struct.custom_align); @@ -703,6 +899,14 @@ gb_internal void write_type_to_canonical_string(TypeWriter *w, Type *type) { if (i > 0) { type_writer_appendc(w, CANONICAL_FIELD_SEPARATOR); } + + if (f->flags & EntityFlags_IsSubtype) { + type_writer_appendc(w, "#subtype "); + } + + if (f->flags & EntityFlag_Using) { + type_writer_appendc(w, "using "); + } type_writer_append(w, f->token.string.text, f->token.string.len); type_writer_appendc(w, CANONICAL_TYPE_SEPARATOR); write_type_to_canonical_string(w, f->type); diff --git a/src/name_canonicalization.hpp b/src/name_canonicalization.hpp index 304aff42e..00b450fbe 100644 --- a/src/name_canonicalization.hpp +++ b/src/name_canonicalization.hpp @@ -102,6 +102,8 @@ gb_internal Type *type_set_add (TypeSet *s, Type *ptr); gb_internal Type *type_set_add (TypeSet *s, TypeInfoPair pair); gb_internal bool type_set_update (TypeSet *s, Type *ptr); // returns true if it previously existed gb_internal bool type_set_update (TypeSet *s, TypeInfoPair pair); // returns true if it previously existed +gb_internal bool type_set_update_with_mutex(TypeSet *s, TypeInfoPair pair, RWSpinLock *m); +gb_internal bool type_set_update_with_mutex(TypeSet *s, Type *ptr, RWSpinLock *m); gb_internal bool type_set_exists (TypeSet *s, Type *ptr); gb_internal void type_set_remove (TypeSet *s, Type *ptr); gb_internal void type_set_clear (TypeSet *s); diff --git a/src/parser.cpp b/src/parser.cpp index a05e183ce..de5655ce1 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -1,5 +1,7 @@ #include "parser_pos.cpp" +gb_global std::atomic<bool> g_parsing_done; + gb_internal bool in_vet_packages(AstFile *file) { if (file == nullptr) { return true; @@ -176,7 +178,11 @@ gb_internal Ast *clone_ast(Ast *node, AstFile *f) { return nullptr; } if (f == nullptr) { - f = node->thread_safe_file(); + if (g_parsing_done.load(std::memory_order_relaxed)) { + f = node->file(); + } else { + f = node->thread_safe_file(); + } } Ast *n = alloc_ast_node(f, node->kind); gb_memmove(n, node, ast_node_size(node->kind)); @@ -744,6 +750,7 @@ gb_internal Ast *ast_matrix_index_expr(AstFile *f, Ast *expr, Token open, Token gb_internal Ast *ast_ident(AstFile *f, Token token) { Ast *result = alloc_ast_node(f, Ast_Ident); result->Ident.token = token; + result->Ident.hash = string_hash(token.string); return result; } @@ -1223,7 +1230,7 @@ gb_internal Ast *ast_dynamic_array_type(AstFile *f, Token token, Ast *elem) { } gb_internal Ast *ast_struct_type(AstFile *f, Token token, Slice<Ast *> fields, isize field_count, - Ast *polymorphic_params, bool is_packed, bool is_raw_union, bool is_no_copy, + Ast *polymorphic_params, bool is_packed, bool is_raw_union, bool is_all_or_none, Ast *align, Ast *min_field_align, Ast *max_field_align, Token where_token, Array<Ast *> const &where_clauses) { Ast *result = alloc_ast_node(f, Ast_StructType); @@ -1233,7 +1240,7 @@ gb_internal Ast *ast_struct_type(AstFile *f, Token token, Slice<Ast *> fields, i result->StructType.polymorphic_params = polymorphic_params; result->StructType.is_packed = is_packed; result->StructType.is_raw_union = is_raw_union; - result->StructType.is_no_copy = is_no_copy; + result->StructType.is_all_or_none = is_all_or_none; result->StructType.align = align; result->StructType.min_field_align = min_field_align; result->StructType.max_field_align = max_field_align; @@ -2732,7 +2739,7 @@ gb_internal Ast *parse_operand(AstFile *f, bool lhs) { while (allow_token(f, Token_Comma)) { Ast *dummy_name = parse_ident(f); if (!err_once) { - error(dummy_name, "'bit_field' fields do not support multiple names per field"); + syntax_error(dummy_name, "'bit_field' fields do not support multiple names per field"); err_once = true; } } @@ -2766,8 +2773,8 @@ gb_internal Ast *parse_operand(AstFile *f, bool lhs) { Token token = expect_token(f, Token_struct); Ast *polymorphic_params = nullptr; bool is_packed = false; + bool is_all_or_none = false; bool is_raw_union = false; - bool no_copy = false; Ast *align = nullptr; Ast *min_field_align = nullptr; Ast *max_field_align = nullptr; @@ -2795,6 +2802,11 @@ gb_internal Ast *parse_operand(AstFile *f, bool lhs) { syntax_error(tag, "Duplicate struct tag '#%.*s'", LIT(tag.string)); } is_packed = true; + } else if (tag.string == "all_or_none") { + if (is_all_or_none) { + syntax_error(tag, "Duplicate struct tag '#%.*s'", LIT(tag.string)); + } + is_all_or_none = true; } else if (tag.string == "align") { if (align) { syntax_error(tag, "Duplicate struct tag '#%.*s'", LIT(tag.string)); @@ -2849,11 +2861,6 @@ gb_internal Ast *parse_operand(AstFile *f, bool lhs) { syntax_error(tag, "Duplicate struct tag '#%.*s'", LIT(tag.string)); } is_raw_union = true; - } else if (tag.string == "no_copy") { - if (no_copy) { - syntax_error(tag, "Duplicate struct tag '#%.*s'", LIT(tag.string)); - } - no_copy = true; } else { syntax_error(tag, "Invalid struct tag '#%.*s'", LIT(tag.string)); } @@ -2865,6 +2872,10 @@ gb_internal Ast *parse_operand(AstFile *f, bool lhs) { is_packed = false; syntax_error(token, "'#raw_union' cannot also be '#packed'"); } + if (is_raw_union && is_all_or_none) { + is_all_or_none = false; + syntax_error(token, "'#raw_union' cannot also be '#all_or_none'"); + } Token where_token = {}; Array<Ast *> where_clauses = {}; @@ -2894,7 +2905,10 @@ gb_internal Ast *parse_operand(AstFile *f, bool lhs) { parser_check_polymorphic_record_parameters(f, polymorphic_params); - return ast_struct_type(f, token, decls, name_count, polymorphic_params, is_packed, is_raw_union, no_copy, align, min_field_align, max_field_align, where_token, where_clauses); + return ast_struct_type(f, token, decls, name_count, + polymorphic_params, is_packed, is_raw_union, is_all_or_none, + align, min_field_align, max_field_align, + where_token, where_clauses); } break; case Token_union: { @@ -3292,8 +3306,16 @@ gb_internal Ast *parse_atom_expr(AstFile *f, Ast *operand, bool lhs) { open = expect_token(f, Token_OpenBracket); if (f->curr_token.kind == Token_CloseBracket) { - error(f->curr_token, "Expected an operand, got ]"); + ERROR_BLOCK(); + syntax_error(f->curr_token, "Expected an operand, got ]"); close = expect_token(f, Token_CloseBracket); + + if (f->allow_type) { + gbString s = expr_to_string(operand); + error_line("\tSuggestion: If a type was wanted, did you mean '[]%s'?", s); + gb_string_free(s); + } + operand = ast_index_expr(f, operand, nullptr, open, close); break; } @@ -6417,6 +6439,7 @@ gb_internal u64 parse_feature_tag(Token token_for_pos, String s) { switch (flag) { case OptInFeatureFlag_IntegerDivisionByZero_Trap: case OptInFeatureFlag_IntegerDivisionByZero_Zero: + case OptInFeatureFlag_IntegerDivisionByZero_AllBits: syntax_error(token_for_pos, "Feature flag does not support notting with '!' - '%.*s'", LIT(p)); break; } @@ -6429,6 +6452,7 @@ gb_internal u64 parse_feature_tag(Token token_for_pos, String s) { error_line("\tinteger-division-by-zero:trap\n"); error_line("\tinteger-division-by-zero:zero\n"); error_line("\tinteger-division-by-zero:self\n"); + error_line("\tinteger-division-by-zero:all-bits\n"); return OptInFeatureFlag_NONE; } } @@ -6554,6 +6578,10 @@ gb_internal bool parse_file_tag(const String &lc, const Token &tok, AstFile *f) } else if (string_starts_with(lc, str_lit("vet"))) { f->vet_flags = parse_vet_tag(tok, lc); f->vet_flags_set = true; + } else if (string_starts_with(lc, str_lit("test"))) { + if ((build_context.command_kind & Command_test) == 0) { + return false; + } } else if (string_starts_with(lc, str_lit("ignore"))) { return false; } else if (string_starts_with(lc, str_lit("private"))) { @@ -6581,7 +6609,7 @@ gb_internal bool parse_file_tag(const String &lc, const Token &tok, AstFile *f) } else if (lc == "no-instrumentation") { f->flags |= AstFile_NoInstrumentation; } else { - error(tok, "Unknown tag '%.*s'", LIT(lc)); + syntax_error(tok, "Unknown tag '%.*s'", LIT(lc)); } return true; @@ -6924,6 +6952,8 @@ gb_internal ParseFileError parse_packages(Parser *p, String init_filename) { } } + g_parsing_done.store(true, std::memory_order_relaxed); + return ParseFile_None; } diff --git a/src/parser.hpp b/src/parser.hpp index d2dd22667..71b61d95f 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -27,10 +27,29 @@ enum AddressingMode : u8 { Addressing_SwizzleVariable = 14, // Swizzle indexed variable }; +gb_global String const addressing_mode_strings[] = { + str_lit("Invalid"), + str_lit("NoValue"), + str_lit("Value"), + str_lit("Context"), + str_lit("Variable"), + str_lit("Constant"), + str_lit("Type"), + str_lit("Builtin"), + str_lit("ProcGroup"), + str_lit("MapIndex"), + str_lit("OptionalOk"), + str_lit("OptionalOkPtr"), + str_lit("SoaVariable"), + str_lit("SwizzleValue"), + str_lit("SwizzleVariable"), +}; + struct TypeAndValue { Type * type; AddressingMode mode; - bool is_lhs; // Debug info + bool is_lhs; // Debug info + Type * objc_super_target; // Original type of the Obj-C object before being converted to the superclass' type by the objc_super() intrinsic. ExactValue value; }; @@ -396,6 +415,7 @@ struct AstSplitArgs { AST_KIND(Ident, "identifier", struct { \ Token token; \ Entity *entity; \ + u32 hash; \ }) \ AST_KIND(Implicit, "implicit", Token) \ AST_KIND(Uninit, "uninitialized value", Token) \ @@ -746,6 +766,7 @@ AST_KIND(_TypeBegin, "", bool) \ bool is_packed; \ bool is_raw_union; \ bool is_no_copy; \ + bool is_all_or_none; \ }) \ AST_KIND(UnionType, "union type", struct { \ Scope *scope; \ diff --git a/src/ptr_map.cpp b/src/ptr_map.cpp index 61f703cf1..6ee3ec16d 100644 --- a/src/ptr_map.cpp +++ b/src/ptr_map.cpp @@ -10,11 +10,31 @@ enum { enum : MapIndex { MAP_SENTINEL = ~(MapIndex)0 }; -static void *const MAP_TOMBSTONE = (void *)~(uintptr)0; + +template <typename T> +struct PtrMapConstant { + static gb_inline T const TOMBSTONE() { + return (T)reinterpret_cast<void *>(~(uintptr)0); + } +}; + +template <> +struct PtrMapConstant<u64> { + static gb_inline u64 const TOMBSTONE() { + return ~(u64)0; + } +}; +template <> +struct PtrMapConstant<i64> { + static gb_inline i64 const TOMBSTONE() { + return ~(i64)0; + } +}; template <typename K, typename V> struct PtrMapEntry { - static_assert(sizeof(K) == sizeof(void *), "Key size must be pointer size"); + static_assert(TypeIsPointer<K>::value || TypeIsPtrSizedInteger<K>::value || TypeIs64BitInteger<K>::value, + "PtrMapEntry::K must be a pointer or 8-byte integer"); K key; V value; @@ -99,7 +119,7 @@ gb_internal void map__insert(PtrMap<K, V> *h, K key, V const &value) { MapIndex original_index = index; do { auto *entry = h->entries+index; - if (!entry->key || entry->key == cast(K)MAP_TOMBSTONE) { + if (!entry->key || entry->key == PtrMapConstant<K>::TOMBSTONE()) { entry->key = key; entry->value = value; h->count += 1; @@ -147,7 +167,7 @@ gb_internal void map_reserve(PtrMap<K, V> *h, isize cap) { for (u32 i = 0; i < h->capacity; i++) { auto *entry = h->entries+i; if (entry->key && - entry->key != cast(K)MAP_TOMBSTONE) { + entry->key != PtrMapConstant<K>::TOMBSTONE()) { map__insert(&new_h, entry->key, entry->value); } } @@ -257,7 +277,7 @@ template <typename K, typename V> gb_internal void map_remove(PtrMap<K, V> *h, K key) { MapIndex found_index = 0; if (map_try_get(h, key, &found_index)) { - h->entries[found_index].key = cast(K)MAP_TOMBSTONE; + h->entries[found_index].key = cast(K)PtrMapConstant<K>::TOMBSTONE(); h->count -= 1; } } @@ -367,7 +387,7 @@ struct PtrMapIterator { return *this; } PtrMapEntry<K, V> *entry = map->entries+index; - if (entry->key && entry->key != cast(K)MAP_TOMBSTONE) { + if (entry->key && entry->key != PtrMapConstant<K>::TOMBSTONE()) { return *this; } } @@ -404,7 +424,7 @@ gb_internal PtrMapIterator<K, V> begin(PtrMap<K, V> &m) noexcept { MapIndex index = 0; while (index < m.capacity) { auto key = m.entries[index].key; - if (key && key != cast(K)MAP_TOMBSTONE) { + if (key && key != PtrMapConstant<K>::TOMBSTONE()) { break; } index++; @@ -420,7 +440,7 @@ gb_internal PtrMapIterator<K, V> const begin(PtrMap<K, V> const &m) noexcept { MapIndex index = 0; while (index < m.capacity) { auto key = m.entries[index].key; - if (key && key != cast(K)MAP_TOMBSTONE) { + if (key && key != PtrMapConstant<K>::TOMBSTONE()) { break; } index++; @@ -447,7 +467,8 @@ struct MapFindResult { template <typename K, typename V> struct OrderedInsertPtrMapEntry { - static_assert(sizeof(K) == sizeof(void *), "Key size must be pointer size"); + static_assert(TypeIsPointer<K>::value || TypeIsPtrSizedInteger<K>::value || TypeIs64BitInteger<K>::value, + "OrderedInsertPtrMapEntry::K must be a pointer or 8-byte integer"); K key; V value; diff --git a/src/ptr_set.cpp b/src/ptr_set.cpp index 5097e2bb6..5b1d2cc19 100644 --- a/src/ptr_set.cpp +++ b/src/ptr_set.cpp @@ -16,6 +16,8 @@ template <typename T> gb_internal bool ptr_set_exists (PtrSet<T> *s, T ptr); template <typename T> gb_internal void ptr_set_remove (PtrSet<T> *s, T ptr); template <typename T> gb_internal void ptr_set_clear (PtrSet<T> *s); +#define FOR_PTR_SET(element, set_) for (auto *it = &(set_).keys[0], element = it ? *it : nullptr; (set_).keys != nullptr && it < &(set_).keys[(set_).capacity]; it++) if (element = *it, (*it != nullptr && *it != cast(void *)~(uintptr)(0ull))) + gb_internal gbAllocator ptr_set_allocator(void) { return heap_allocator(); } @@ -83,7 +85,7 @@ gb_internal gb_inline void ptr_set_grow(PtrSet<T> *old_set) { PtrSet<T> new_set = {}; ptr_set_init(&new_set, gb_max(old_set->capacity<<1, 16)); - for (T ptr : *old_set) { + FOR_PTR_SET(ptr, *old_set) { bool was_new = ptr_set_update(&new_set, ptr); GB_ASSERT(!was_new); } @@ -135,6 +137,44 @@ gb_internal bool ptr_set_update(PtrSet<T> *s, T ptr) { // returns true if it pre } template <typename T> +gb_internal bool ptr_set_update_with_mutex(PtrSet<T> *s, T ptr, RWSpinLock *m) { // returns true if it previously existsed + rwlock_acquire_upgrade(m); + if (ptr_set_exists(s, ptr)) { + rwlock_release_upgrade(m); + return true; + } + + rwlock_release_upgrade_and_acquire_write(m); + defer (rwlock_release_write(m)); + + if (s->keys == nullptr) { + ptr_set_init(s); + } else if (ptr_set__full(s)) { + ptr_set_grow(s); + } + GB_ASSERT(s->count < s->capacity); + GB_ASSERT(s->capacity >= 0); + + usize mask = s->capacity-1; + u32 hash = ptr_map_hash_key(ptr); + usize hash_index = (cast(usize)hash) & mask; + GB_ASSERT(hash_index < s->capacity); + for (usize i = 0; i < s->capacity; i++) { + T *key = &s->keys[hash_index]; + GB_ASSERT(*key != ptr); + if (*key == (T)PtrSet<T>::TOMBSTONE || *key == 0) { + *key = ptr; + s->count++; + return false; + } + hash_index = (hash_index+1)&mask; + } + + GB_PANIC("ptr set out of memory"); + return false; +} + +template <typename T> gb_internal T ptr_set_add(PtrSet<T> *s, T ptr) { ptr_set_update(s, ptr); return ptr; @@ -157,7 +197,7 @@ gb_internal gb_inline void ptr_set_clear(PtrSet<T> *s) { gb_zero_size(s->keys, s->capacity*gb_size_of(T)); } -template <typename T> +/*template <typename T> struct PtrSetIterator { PtrSet<T> *set; usize index; @@ -201,4 +241,6 @@ gb_internal PtrSetIterator<T> begin(PtrSet<T> &set) noexcept { template <typename T> gb_internal PtrSetIterator<T> end(PtrSet<T> &set) noexcept { return PtrSetIterator<T>{&set, set.capacity}; -}
\ No newline at end of file +}*/ + + diff --git a/src/queue.cpp b/src/queue.cpp index dee9ad1f8..82f82f3e1 100644 --- a/src/queue.cpp +++ b/src/queue.cpp @@ -36,7 +36,8 @@ gb_internal void mpsc_destroy(MPSCQueue<T> *q) { template <typename T> gb_internal MPSCNode<T> *mpsc_alloc_node(MPSCQueue<T> *q, T const &value) { - auto new_node = gb_alloc_item(heap_allocator(), MPSCNode<T>); + // auto new_node = gb_alloc_item(heap_allocator(), MPSCNode<T>); + auto new_node = gb_alloc_item(permanent_allocator(), MPSCNode<T>); new_node->value = value; return new_node; } diff --git a/src/string.cpp b/src/string.cpp index 2087a5fee..9c08114a7 100644 --- a/src/string.cpp +++ b/src/string.cpp @@ -633,23 +633,28 @@ gb_internal String normalize_path(gbAllocator a, String const &path, String cons return WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, widechar_input, input_length, output, output_size, nullptr, nullptr); } #elif defined(GB_SYSTEM_UNIX) || defined(GB_SYSTEM_OSX) - - #include <iconv.h> + #include <wchar.h> gb_internal int convert_multibyte_to_widechar(char const *multibyte_input, usize input_length, wchar_t *output, usize output_size) { - iconv_t conv = iconv_open("WCHAR_T", "UTF-8"); - size_t result = iconv(conv, cast(char **)&multibyte_input, &input_length, cast(char **)&output, &output_size); - iconv_close(conv); + String string = copy_string(heap_allocator(), make_string(cast(u8 const*)multibyte_input, input_length)); /* Guarantee NULL terminator */ + u8* input = string.text; + + mbstate_t ps = { 0 }; + size_t result = mbsrtowcs(output, cast(const char**)&input, output_size, &ps); - return cast(int)result; + gb_free(heap_allocator(), string.text); + return (result == (size_t)-1) ? -1 : (int)result; } gb_internal int convert_widechar_to_multibyte(wchar_t const *widechar_input, usize input_length, char* output, usize output_size) { - iconv_t conv = iconv_open("UTF-8", "WCHAR_T"); - size_t result = iconv(conv, cast(char**) &widechar_input, &input_length, cast(char **)&output, &output_size); - iconv_close(conv); + String string = copy_string(heap_allocator(), make_string(cast(u8 const*)widechar_input, input_length)); /* Guarantee NULL terminator */ + u8* input = string.text; + + mbstate_t ps = { 0 }; + size_t result = wcsrtombs(output, cast(const wchar_t**)&input, output_size, &ps); - return cast(int)result; + gb_free(heap_allocator(), string.text); + return (result == (size_t)-1) ? -1 : (int)result; } #else #error Implement system diff --git a/src/thread_pool.cpp b/src/thread_pool.cpp index 8363a4553..ca6483fd9 100644 --- a/src/thread_pool.cpp +++ b/src/thread_pool.cpp @@ -19,6 +19,11 @@ enum GrabState { Grab_Failed = 2, }; +enum BroadcastWaitState { + Nobody_Waiting = 0, + Someone_Waiting = 1, +}; + struct ThreadPool { gbAllocator threads_allocator; Slice<Thread> threads; @@ -54,8 +59,8 @@ gb_internal void thread_pool_destroy(ThreadPool *pool) { for_array_off(i, 1, pool->threads) { Thread *t = &pool->threads[i]; - pool->tasks_available.fetch_add(1, std::memory_order_acquire); - futex_broadcast(&pool->tasks_available); + pool->tasks_available.store(Nobody_Waiting); + futex_broadcast(&t->pool->tasks_available); thread_join_and_destroy(t); } @@ -87,8 +92,10 @@ void thread_pool_queue_push(Thread *thread, WorkerTask task) { thread->queue.bottom.store(bot + 1, std::memory_order_relaxed); thread->pool->tasks_left.fetch_add(1, std::memory_order_release); - thread->pool->tasks_available.fetch_add(1, std::memory_order_relaxed); - futex_broadcast(&thread->pool->tasks_available); + i32 state = Someone_Waiting; + if (thread->pool->tasks_available.compare_exchange_strong(state, Nobody_Waiting)) { + futex_broadcast(&thread->pool->tasks_available); + } } GrabState thread_pool_queue_take(Thread *thread, WorkerTask *task) { @@ -230,12 +237,13 @@ gb_internal THREAD_PROC(thread_pool_thread_proc) { } // if we've done all our work, and there's nothing to steal, go to sleep - state = pool->tasks_available.load(std::memory_order_acquire); + pool->tasks_available.store(Someone_Waiting); if (!pool->running) { break; } - futex_wait(&pool->tasks_available, state); + futex_wait(&pool->tasks_available, Someone_Waiting); main_loop_continue:; } return 0; } + diff --git a/src/threading.cpp b/src/threading.cpp index a0d1c4049..02e6de14b 100644 --- a/src/threading.cpp +++ b/src/threading.cpp @@ -195,7 +195,13 @@ gb_internal void mutex_lock(RecursiveMutex *m) { // inside the lock return; } - futex_wait(&m->owner, prev_owner); + + // NOTE(lucas): we are doing spin lock since futex signal is expensive on OSX. The recursive locks are + // very short lived so we don't hit this mega often and I see no perform regression on windows (with + // a performance uplift on OSX). + + //futex_wait(&m->owner, prev_owner); + yield_thread(); } } gb_internal bool mutex_try_lock(RecursiveMutex *m) { @@ -216,7 +222,9 @@ gb_internal void mutex_unlock(RecursiveMutex *m) { return; } m->owner.exchange(0, std::memory_order_release); - futex_signal(&m->owner); + // NOTE(lucas): see comment about spin lock in mutex_lock above + + // futex_signal(&m->owner); // outside the lock } @@ -448,6 +456,45 @@ gb_internal void semaphore_wait(Semaphore *s) { } #endif +static const int RWLOCK_WRITER = 1<<0; +static const int RWLOCK_UPGRADED = 1<<1; +static const int RWLOCK_READER = 1<<2; +struct RWSpinLock { + Futex bits; +}; + +void rwlock_release_write(RWSpinLock *l) { + l->bits.fetch_and(~(RWLOCK_WRITER | RWLOCK_UPGRADED), std::memory_order_release); + futex_signal(&l->bits); +} + +bool rwlock_try_acquire_upgrade(RWSpinLock *l) { + int value = l->bits.fetch_or(RWLOCK_UPGRADED, std::memory_order_acquire); + return (value & (RWLOCK_UPGRADED | RWLOCK_WRITER)) == 0; +} + +void rwlock_acquire_upgrade(RWSpinLock *l) { + while (!rwlock_try_acquire_upgrade(l)) { + futex_wait(&l->bits, RWLOCK_UPGRADED | RWLOCK_WRITER); + } +} +void rwlock_release_upgrade(RWSpinLock *l) { + l->bits.fetch_add(-RWLOCK_UPGRADED, std::memory_order_acq_rel); + futex_signal(&l->bits); +} + +bool rwlock_try_release_upgrade_and_acquire_write(RWSpinLock *l) { + int expect = RWLOCK_UPGRADED; + return l->bits.compare_exchange_strong(expect, RWLOCK_WRITER, std::memory_order_acq_rel); +} + +void rwlock_release_upgrade_and_acquire_write(RWSpinLock *l) { + while (!rwlock_try_release_upgrade_and_acquire_write(l)) { + futex_wait(&l->bits, RWLOCK_UPGRADED); + } +} + + struct Parker { Futex state; }; diff --git a/src/tilde_type_info.cpp b/src/tilde_type_info.cpp index 58e8d3087..96a101376 100644 --- a/src/tilde_type_info.cpp +++ b/src/tilde_type_info.cpp @@ -783,14 +783,13 @@ gb_internal void cg_setup_type_info_data(cgModule *m) { i64 is_packed_offset = type_offset_of(tag_type, 5); i64 is_raw_union_offset = type_offset_of(tag_type, 6); - i64 is_no_copy_offset = type_offset_of(tag_type, 7); - i64 custom_align_offset = type_offset_of(tag_type, 8); + i64 custom_align_offset = type_offset_of(tag_type, 7); - i64 equal_offset = type_offset_of(tag_type, 9); + i64 equal_offset = type_offset_of(tag_type, 8); - i64 soa_kind_offset = type_offset_of(tag_type, 10); - i64 soa_base_type_offset = type_offset_of(tag_type, 11); - i64 soa_len_offset = type_offset_of(tag_type, 12); + i64 soa_kind_offset = type_offset_of(tag_type, 9); + i64 soa_base_type_offset = type_offset_of(tag_type, 10); + i64 soa_len_offset = type_offset_of(tag_type, 11); // TODO(bill): equal proc stuff gb_unused(equal_offset); @@ -825,7 +824,6 @@ gb_internal void cg_setup_type_info_data(cgModule *m) { set_bool(m, global, offset+is_packed_offset, t->Struct.is_packed); set_bool(m, global, offset+is_raw_union_offset, t->Struct.is_raw_union); - set_bool(m, global, offset+is_no_copy_offset, t->Struct.is_no_copy); set_bool(m, global, offset+custom_align_offset, t->Struct.custom_align != 0); if (t->Struct.soa_kind != StructSoa_None) { diff --git a/src/types.cpp b/src/types.cpp index c465714db..18e3b56ac 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -2,6 +2,9 @@ struct Ast; struct Scope; struct Entity; +// NOTE(Jeroen): Minimum alignment for #load(file, <type>) slices +#define MINIMUM_SLICE_ALIGNMENT 16 + enum BasicKind { Basic_Invalid, @@ -159,6 +162,7 @@ struct TypeStruct { bool are_offsets_set : 1; bool is_packed : 1; bool is_raw_union : 1; + bool is_all_or_none : 1; bool is_poly_specialized : 1; std::atomic<bool> are_offsets_being_processed; @@ -206,13 +210,18 @@ struct TypeProc { bool optional_ok; }; +struct TypeNamed { + String name; + Type * base; + Entity *type_name; /* Entity_TypeName */ + + BlockingMutex gen_types_data_mutex; + GenTypesData *gen_types_data; +}; + #define TYPE_KINDS \ TYPE_KIND(Basic, BasicType) \ - TYPE_KIND(Named, struct { \ - String name; \ - Type * base; \ - Entity *type_name; /* Entity_TypeName */ \ - }) \ + TYPE_KIND(Named, TypeNamed) \ TYPE_KIND(Generic, struct { \ i64 id; \ String name; \ @@ -334,6 +343,7 @@ struct Type { // NOTE(bill): These need to be at the end to not affect the unionized data std::atomic<i64> cached_size; std::atomic<i64> cached_align; + std::atomic<u64> canonical_hash; std::atomic<u32> flags; // TypeFlag bool failure; }; @@ -404,7 +414,7 @@ gb_internal u32 type_info_flags_of_type(Type *type) { flags |= TypeInfoFlag_Comparable; } if (is_type_simple_compare(type)) { - flags |= TypeInfoFlag_Comparable; + flags |= TypeInfoFlag_Comparable|TypeInfoFlag_Simple_Compare; } return flags; } @@ -429,11 +439,8 @@ gb_internal Selection make_selection(Entity *entity, Array<i32> index, bool indi } gb_internal void selection_add_index(Selection *s, isize index) { - // IMPORTANT NOTE(bill): this requires a stretchy buffer/dynamic array so it requires some form - // of heap allocation - // TODO(bill): Find a way to use a backing buffer for initial use as the general case is probably .count<3 if (s->index.data == nullptr) { - array_init(&s->index, heap_allocator()); + array_init(&s->index, permanent_allocator()); } array_add(&s->index, cast(i32)index); } @@ -441,7 +448,7 @@ gb_internal void selection_add_index(Selection *s, isize index) { gb_internal Selection selection_combine(Selection const &lhs, Selection const &rhs) { Selection new_sel = lhs; new_sel.indirect = lhs.indirect || rhs.indirect; - new_sel.index = array_make<i32>(heap_allocator(), lhs.index.count+rhs.index.count); + new_sel.index = array_make<i32>(permanent_allocator(), lhs.index.count+rhs.index.count); array_copy(&new_sel.index, lhs.index, 0); array_copy(&new_sel.index, rhs.index, lhs.index.count); return new_sel; @@ -749,11 +756,14 @@ gb_global Type *t_objc_object = nullptr; gb_global Type *t_objc_selector = nullptr; gb_global Type *t_objc_class = nullptr; gb_global Type *t_objc_ivar = nullptr; +gb_global Type *t_objc_super = nullptr; // Struct used in lieu of the 'self' instance when calling objc_msgSendSuper. +gb_global Type *t_objc_super_ptr = nullptr; gb_global Type *t_objc_id = nullptr; gb_global Type *t_objc_SEL = nullptr; gb_global Type *t_objc_Class = nullptr; gb_global Type *t_objc_Ivar = nullptr; +gb_global Type *t_objc_instancetype = nullptr; // Special distinct variant of t_objc_id used mimic auto-typing of instancetype* in Objective-C enum OdinAtomicMemoryOrder : i32 { OdinAtomicMemoryOrder_relaxed = 0, // unordered @@ -1230,7 +1240,6 @@ gb_internal bool is_type_named(Type *t) { } gb_internal bool is_type_boolean(Type *t) { - // t = core_type(t); t = base_type(t); if (t == nullptr) { return false; } if (t->kind == Type_Basic) { @@ -1239,7 +1248,6 @@ gb_internal bool is_type_boolean(Type *t) { return false; } gb_internal bool is_type_integer(Type *t) { - // t = core_type(t); t = base_type(t); if (t == nullptr) { return false; } if (t->kind == Type_Basic) { @@ -1249,6 +1257,7 @@ gb_internal bool is_type_integer(Type *t) { } gb_internal bool is_type_integer_like(Type *t) { t = core_type(t); + if (t == nullptr) { return false; } if (t->kind == Type_Basic) { return (t->Basic.flags & (BasicFlag_Integer|BasicFlag_Boolean)) != 0; } @@ -1281,7 +1290,6 @@ gb_internal bool is_type_integer_128bit(Type *t) { return false; } gb_internal bool is_type_rune(Type *t) { - // t = core_type(t); t = base_type(t); if (t == nullptr) { return false; } if (t->kind == Type_Basic) { @@ -1289,8 +1297,16 @@ gb_internal bool is_type_rune(Type *t) { } return false; } +gb_internal bool is_type_integer_or_float(Type *t) { + t = base_type(t); + if (t == nullptr) { return false; } + if (t->kind == Type_Basic) { + return (t->Basic.flags & (BasicFlag_Integer|BasicFlag_Float)) != 0; + } + return false; +} + gb_internal bool is_type_numeric(Type *t) { - // t = core_type(t); t = base_type(t); if (t == nullptr) { return false; } if (t->kind == Type_Basic) { @@ -1377,14 +1393,20 @@ gb_internal bool is_type_ordered_numeric(Type *t) { gb_internal bool is_type_constant_type(Type *t) { t = core_type(t); if (t == nullptr) { return false; } - if (t->kind == Type_Basic) { + switch (t->kind) { + case Type_Basic: + if (t->Basic.kind == Basic_typeid) { + return true; + } return (t->Basic.flags & BasicFlag_ConstantType) != 0; - } - if (t->kind == Type_BitSet) { + case Type_BitSet: return true; - } - if (t->kind == Type_Proc) { + case Type_Proc: return true; + case Type_Array: + return is_type_constant_type(t->Array.elem); + case Type_EnumeratedArray: + return is_type_constant_type(t->EnumeratedArray.elem); } return false; } @@ -1448,24 +1470,28 @@ gb_internal bool is_type_tuple(Type *t) { return t->kind == Type_Tuple; } gb_internal bool is_type_uintptr(Type *t) { + if (t == nullptr) { return false; } if (t->kind == Type_Basic) { return (t->Basic.kind == Basic_uintptr); } return false; } gb_internal bool is_type_rawptr(Type *t) { + if (t == nullptr) { return false; } if (t->kind == Type_Basic) { return t->Basic.kind == Basic_rawptr; } return false; } gb_internal bool is_type_u8(Type *t) { + if (t == nullptr) { return false; } if (t->kind == Type_Basic) { return t->Basic.kind == Basic_u8; } return false; } gb_internal bool is_type_u16(Type *t) { + if (t == nullptr) { return false; } if (t->kind == Type_Basic) { return t->Basic.kind == Basic_u16; } @@ -1612,6 +1638,7 @@ gb_internal bool is_matrix_square(Type *t) { gb_internal bool is_type_valid_for_matrix_elems(Type *t) { t = base_type(t); + if (t == nullptr) { return false; } if (is_type_integer(t)) { return true; } else if (is_type_float(t)) { @@ -1711,7 +1738,7 @@ gb_internal bool is_type_u8_ptr(Type *t) { t = base_type(t); if (t == nullptr) { return false; } if (t->kind == Type_Pointer) { - return is_type_u8(t->Slice.elem); + return is_type_u8(t->Pointer.elem); } return false; } @@ -1752,7 +1779,7 @@ gb_internal bool is_type_u16_ptr(Type *t) { t = base_type(t); if (t == nullptr) { return false; } if (t->kind == Type_Pointer) { - return is_type_u16(t->Slice.elem); + return is_type_u16(t->Pointer.elem); } return false; } @@ -1839,40 +1866,49 @@ gb_internal Type *base_complex_elem_type(Type *t) { gb_internal bool is_type_struct(Type *t) { t = base_type(t); + if (t == nullptr) { return false; } return t->kind == Type_Struct; } gb_internal bool is_type_union(Type *t) { t = base_type(t); + if (t == nullptr) { return false; } return t->kind == Type_Union; } gb_internal bool is_type_soa_struct(Type *t) { t = base_type(t); + if (t == nullptr) { return false; } return t->kind == Type_Struct && t->Struct.soa_kind != StructSoa_None; } gb_internal bool is_type_raw_union(Type *t) { t = base_type(t); + if (t == nullptr) { return false; } return (t->kind == Type_Struct && t->Struct.is_raw_union); } gb_internal bool is_type_enum(Type *t) { t = base_type(t); + if (t == nullptr) { return false; } return (t->kind == Type_Enum); } gb_internal bool is_type_bit_set(Type *t) { t = base_type(t); + if (t == nullptr) { return false; } return (t->kind == Type_BitSet); } gb_internal bool is_type_bit_field(Type *t) { t = base_type(t); + if (t == nullptr) { return false; } return (t->kind == Type_BitField); } gb_internal bool is_type_map(Type *t) { t = base_type(t); + if (t == nullptr) { return false; } return t->kind == Type_Map; } gb_internal bool is_type_union_maybe_pointer(Type *t) { t = base_type(t); + if (t == nullptr) { return false; } if (t->kind == Type_Union && t->Union.variants.count == 1) { Type *v = t->Union.variants[0]; return is_type_internally_pointer_like(v); @@ -1883,6 +1919,7 @@ gb_internal bool is_type_union_maybe_pointer(Type *t) { gb_internal bool is_type_union_maybe_pointer_original_alignment(Type *t) { t = base_type(t); + if (t == nullptr) { return false; } if (t->kind == Type_Union && t->Union.variants.count == 1) { Type *v = t->Union.variants[0]; if (is_type_internally_pointer_like(v)) { @@ -1917,6 +1954,7 @@ gb_internal TypeEndianKind type_endian_kind_of(Type *t) { gb_internal bool is_type_endian_big(Type *t) { t = core_type(t); + if (t == nullptr) { return false; } if (t->kind == Type_Basic) { if (t->Basic.flags & BasicFlag_EndianBig) { return true; @@ -1933,6 +1971,7 @@ gb_internal bool is_type_endian_big(Type *t) { } gb_internal bool is_type_endian_little(Type *t) { t = core_type(t); + if (t == nullptr) { return false; } if (t->kind == Type_Basic) { if (t->Basic.flags & BasicFlag_EndianLittle) { return true; @@ -1950,6 +1989,7 @@ gb_internal bool is_type_endian_little(Type *t) { gb_internal bool is_type_endian_platform(Type *t) { t = core_type(t); + if (t == nullptr) { return false; } if (t->kind == Type_Basic) { return (t->Basic.flags & (BasicFlag_EndianLittle|BasicFlag_EndianBig)) == 0; } else if (t->kind == Type_BitSet) { @@ -1965,6 +2005,7 @@ gb_internal bool types_have_same_internal_endian(Type *a, Type *b) { } gb_internal bool is_type_endian_specific(Type *t) { t = core_type(t); + if (t == nullptr) { return false; } if (t->kind == Type_BitSet) { t = bit_set_to_int(t); } @@ -2062,19 +2103,23 @@ gb_internal Type *integer_endian_type_to_platform_type(Type *t) { gb_internal bool is_type_any(Type *t) { t = base_type(t); + if (t == nullptr) { return false; } return (t->kind == Type_Basic && t->Basic.kind == Basic_any); } gb_internal bool is_type_typeid(Type *t) { t = base_type(t); + if (t == nullptr) { return false; } return (t->kind == Type_Basic && t->Basic.kind == Basic_typeid); } gb_internal bool is_type_untyped_nil(Type *t) { t = base_type(t); + if (t == nullptr) { return false; } // NOTE(bill): checking for `nil` or `---` at once is just to improve the error handling return (t->kind == Type_Basic && (t->Basic.kind == Basic_UntypedNil || t->Basic.kind == Basic_UntypedUninit)); } gb_internal bool is_type_untyped_uninit(Type *t) { t = base_type(t); + if (t == nullptr) { return false; } // NOTE(bill): checking for `nil` or `---` at once is just to improve the error handling return (t->kind == Type_Basic && t->Basic.kind == Basic_UntypedUninit); } @@ -2484,18 +2529,70 @@ gb_internal bool type_has_nil(Type *t) { return false; } +gb_internal bool is_type_union_constantable(Type *type) { + Type *bt = base_type(type); + GB_ASSERT(bt->kind == Type_Union); + + if (bt->Union.variants.count == 0) { + return true; + } else if (bt->Union.variants.count == 1) { + return is_type_constant_type(bt->Union.variants[0]); + } + + for (Type *v : bt->Union.variants) { + if (!is_type_constant_type(v)) { + return false; + } + } + return true; +} + +gb_internal bool is_type_raw_union_constantable(Type *type) { + Type *bt = base_type(type); + GB_ASSERT(bt->kind == Type_Struct); + GB_ASSERT(bt->Struct.is_raw_union); + + for (Entity *f : bt->Struct.fields) { + if (!is_type_constant_type(f->type)) { + return false; + } + } + // return true; + return false; // Disable raw union constants for the time being +} + gb_internal bool elem_type_can_be_constant(Type *t) { t = base_type(t); if (t == t_invalid) { return false; } - if (is_type_any(t) || is_type_union(t) || is_type_raw_union(t)) { + if (is_type_any(t)) { return false; } + if (is_type_raw_union(t)) { + return is_type_raw_union_constantable(t); + } + if (is_type_union(t)) { + return is_type_union_constantable(t); + } return true; } +gb_internal bool elem_cannot_be_constant(Type *t) { + if (is_type_any(t)) { + return true; + } + if (is_type_union(t)) { + return !is_type_union_constantable(t); + } + if (is_type_raw_union(t)) { + return !is_type_raw_union_constantable(t); + } + return false; +} + + gb_internal bool is_type_lock_free(Type *t) { t = core_type(t); if (t == t_invalid) { @@ -2837,6 +2934,7 @@ gb_internal bool are_types_identical(Type *x, Type *y) { return false; } + // MUTEX_GUARD(&g_type_mutex); return are_types_identical_internal(x, y, false); } gb_internal bool are_types_identical_unique_tuples(Type *x, Type *y) { @@ -2864,6 +2962,7 @@ gb_internal bool are_types_identical_unique_tuples(Type *x, Type *y) { return false; } + // MUTEX_GUARD(&g_type_mutex); return are_types_identical_internal(x, y, true); } @@ -2986,9 +3085,10 @@ gb_internal bool are_types_identical_internal(Type *x, Type *y, bool check_tuple break; case Type_Struct: - if (x->Struct.is_raw_union == y->Struct.is_raw_union && - x->Struct.fields.count == y->Struct.fields.count && - x->Struct.is_packed == y->Struct.is_packed && + if (x->Struct.is_raw_union == y->Struct.is_raw_union && + x->Struct.fields.count == y->Struct.fields.count && + x->Struct.is_packed == y->Struct.is_packed && + x->Struct.is_all_or_none == y->Struct.is_all_or_none && x->Struct.soa_kind == y->Struct.soa_kind && x->Struct.soa_count == y->Struct.soa_count && are_types_identical(x->Struct.soa_elem, y->Struct.soa_elem)) { @@ -3932,7 +4032,7 @@ gb_internal i64 type_size_of(Type *t) { TypePath path{}; type_path_init(&path); { - MUTEX_GUARD(&g_type_mutex); + // MUTEX_GUARD(&g_type_mutex); size = type_size_of_internal(t, &path); t->cached_size.store(size); } @@ -3952,7 +4052,7 @@ gb_internal i64 type_align_of(Type *t) { TypePath path{}; type_path_init(&path); { - MUTEX_GUARD(&g_type_mutex); + // MUTEX_GUARD(&g_type_mutex); t->cached_align.store(type_align_of_internal(t, &path)); } type_path_free(&path); @@ -4178,6 +4278,9 @@ gb_internal i64 *type_set_offsets_of(Slice<Entity *> const &fields, bool is_pack gb_internal bool type_set_offsets(Type *t) { t = base_type(t); if (t->kind == Type_Struct) { + if (t->Struct.are_offsets_being_processed.load()) { + return true; + } MUTEX_GUARD(&t->Struct.offset_mutex); if (!t->Struct.are_offsets_set) { t->Struct.are_offsets_being_processed.store(true); @@ -4479,6 +4582,8 @@ gb_internal i64 type_offset_of(Type *t, i64 index, Type **field_type_) { case 1: if (field_type_) *field_type_ = t_typeid; return 8; // id + default: + GB_PANIC("index > 1"); } } break; @@ -4556,6 +4661,7 @@ gb_internal i64 type_offset_of_from_selection(Type *type, Selection sel) { switch (index) { case 0: t = t_rawptr; break; case 1: t = t_typeid; break; + default: GB_PANIC("index > 1"); } } break; @@ -4652,6 +4758,14 @@ gb_internal bool is_type_objc_object(Type *t) { return internal_check_is_assignable_to(t, t_objc_object); } +gb_internal bool is_type_objc_ptr_to_object(Type *t) { + // NOTE (harold): is_type_objc_object() returns true if it's a pointer to an object or the object itself. + // This returns true ONLY if Type is a shallow pointer to an Objective-C object. + + Type *elem = type_deref(t); + return elem != t && elem->kind == Type_Named && is_type_objc_object(elem); +} + gb_internal Type *get_struct_field_type(Type *t, isize index) { t = base_type(type_deref(t)); GB_ASSERT(t->kind == Type_Struct); @@ -4678,7 +4792,7 @@ gb_internal Type *alloc_type_tuple_from_field_types(Type **field_types, isize fi } Type *t = alloc_type_tuple(); - t->Tuple.variables = slice_make<Entity *>(heap_allocator(), field_count); + t->Tuple.variables = slice_make<Entity *>(permanent_allocator(), field_count); Scope *scope = nullptr; for_array(i, t->Tuple.variables) { @@ -4813,7 +4927,7 @@ gb_internal Type *type_internal_index(Type *t, isize index) { case Type_Slice: { GB_ASSERT(index == 0 || index == 1); - return index == 0 ? t_rawptr : t_typeid; + return index == 0 ? t_rawptr : t_int; } case Type_DynamicArray: { diff --git a/src/ucg/ucg.c b/src/ucg/ucg.c index c3e270e1a..119f88805 100644 --- a/src/ucg/ucg.c +++ b/src/ucg/ucg.c @@ -1,6 +1,6 @@ /* * SPDX-FileCopyrightText: (c) 2024 Feoramund - * SPDX-License-Identifier: BSD-3-Clause + * SPDX-License-Identifier: zlib */ diff --git a/src/ucg/ucg_tables.h b/src/ucg/ucg_tables.h index a33f9f898..f31e51773 100644 --- a/src/ucg/ucg_tables.h +++ b/src/ucg/ucg_tables.h @@ -1,6 +1,6 @@ /* * SPDX-FileCopyrightText: (c) 2024 Feoramund - * SPDX-License-Identifier: BSD-3-Clause + * SPDX-License-Identifier: zlib */ #ifndef _UCG_TABLES_INCLUDED #define _UCG_TABLES_INCLUDED |