|
87 | 87 |
|
88 | 88 | #if defined(_CPU_ARM_) || defined(_CPU_AARCH64_)
|
89 | 89 | # include <llvm/IR/InlineAsm.h>
|
| 90 | +# include <sys/utsname.h> |
90 | 91 | #endif
|
91 | 92 | #if defined(USE_POLLY)
|
92 | 93 | #include <polly/RegisterPasses.h>
|
@@ -5562,10 +5563,68 @@ static void init_julia_llvm_env(Module *m)
|
5562 | 5563 | addOptimizationPasses(jl_globalPM);
|
5563 | 5564 | }
|
5564 | 5565 |
|
| 5566 | +static inline std::string getNativeTarget() |
| 5567 | +{ |
| 5568 | + std::string cpu = sys::getHostCPUName(); |
| 5569 | +#if defined(_CPU_ARM_) |
| 5570 | + // Try slightly harder than LLVM at determine the CPU architecture. |
| 5571 | + if (cpu == "generic") { |
| 5572 | + // This is the most reliable way I can find |
| 5573 | + // `/proc/cpuinfo` changes between kernel versions |
| 5574 | + struct utsname name; |
| 5575 | + if (uname(&name) >= 0) { |
| 5576 | + // name.machine is the elf_platform in the kernel. |
| 5577 | + if (strcmp(name.machine, "armv6l") == 0) { |
| 5578 | + return "armv6"; |
| 5579 | + } |
| 5580 | + if (strcmp(name.machine, "armv7l") == 0) { |
| 5581 | + return "armv7"; |
| 5582 | + } |
| 5583 | + if (strcmp(name.machine, "armv7ml") == 0) { |
| 5584 | + // Thumb |
| 5585 | + return "armv7-m"; |
| 5586 | + } |
| 5587 | + if (strcmp(name.machine, "armv8l") == 0 || |
| 5588 | + strcmp(name.machine, "aarch64") == 0) { |
| 5589 | + return "armv8"; |
| 5590 | + } |
| 5591 | + } |
| 5592 | + } |
| 5593 | +#endif |
| 5594 | + return cpu; |
| 5595 | +} |
| 5596 | + |
| 5597 | +#if defined(_CPU_ARM_) || defined(_CPU_AARCH64_) |
| 5598 | +// Check if the cpu name is a ARM/AArch64 arch name and return a |
| 5599 | +// string that can be used as LLVM feature name |
| 5600 | +static inline std::string checkARMArchFeature(const std::string &cpu) |
| 5601 | +{ |
| 5602 | + const char *prefix = "armv"; |
| 5603 | + size_t prefix_len = strlen(prefix); |
| 5604 | + if (cpu.size() <= prefix_len || |
| 5605 | + memcmp(cpu.data(), prefix, prefix_len) != 0 || |
| 5606 | + cpu[prefix_len] < '1' || cpu[prefix_len] > '9') |
| 5607 | + return std::string(); |
| 5608 | +#if defined(_CPU_ARM_) |
| 5609 | + // "v7" and "v8" are not available in the form of `armv*` |
| 5610 | + // in the feature list |
| 5611 | + if (cpu == "armv7") { |
| 5612 | + return "v7"; |
| 5613 | + } |
| 5614 | + else if (cpu == "armv8") { |
| 5615 | + return "v8"; |
| 5616 | + } |
| 5617 | + return cpu; |
| 5618 | +#else |
| 5619 | + return cpu.substr(3); |
| 5620 | +#endif |
| 5621 | +} |
| 5622 | +#endif |
| 5623 | + |
5565 | 5624 | // Helper to figure out what features to set for the LLVM target
|
5566 | 5625 | // If the user specifies native (or does not specify) we default
|
5567 | 5626 | // using the API provided by LLVM
|
5568 |
| -static inline SmallVector<std::string,10> getTargetFeatures() |
| 5627 | +static inline SmallVector<std::string,10> getTargetFeatures(std::string &cpu) |
5569 | 5628 | {
|
5570 | 5629 | StringMap<bool> HostFeatures;
|
5571 | 5630 | if (!strcmp(jl_options.cpu_target,"native")) {
|
@@ -5594,16 +5653,63 @@ static inline SmallVector<std::string,10> getTargetFeatures()
|
5594 | 5653 | #endif
|
5595 | 5654 |
|
5596 | 5655 | // Figure out if we know the cpu_target
|
5597 |
| - std::string cpu = strcmp(jl_options.cpu_target,"native") ? jl_options.cpu_target : sys::getHostCPUName(); |
5598 |
| - if (cpu.empty() || cpu == "generic") { |
5599 |
| - jl_printf(JL_STDERR, "WARNING: unable to determine host cpu name.\n"); |
5600 |
| -#if defined(_CPU_ARM_) && defined(__ARM_PCS_VFP) |
5601 |
| - // Check if this is required when you have read the features directly from the processor |
5602 |
| - // This affects the platform calling convention. |
5603 |
| - // TODO: enable vfp3 for ARMv7+ (but adapt the ABI) |
5604 |
| - HostFeatures["vfp2"] = true; |
5605 |
| -#endif |
| 5656 | + cpu = (strcmp(jl_options.cpu_target,"native") ? jl_options.cpu_target : |
| 5657 | + getNativeTarget()); |
| 5658 | +#if defined(_CPU_ARM_) |
| 5659 | + // Figure out what we are compiling against from the C defines. |
| 5660 | + // This might affect ABI but is fine since |
| 5661 | + // 1. We define the C ABI explicitly. |
| 5662 | + // 2. This does not change when running the same binary on different |
| 5663 | + // machines. |
| 5664 | + // This shouldn't affect making generic binaries since that requires a |
| 5665 | + // generic C -march anyway. |
| 5666 | + HostFeatures["vfp2"] = true; |
| 5667 | + |
| 5668 | + // Arch version |
| 5669 | +#if __ARM_ARCH >= 8 |
| 5670 | + HostFeatures["v8"] = true; |
| 5671 | +#elif __ARM_ARCH >= 7 |
| 5672 | + HostFeatures["v7"] = true; |
| 5673 | +#else |
| 5674 | + // minimum requirement |
| 5675 | + HostFeatures["v6"] = true; |
| 5676 | +#endif |
| 5677 | + |
| 5678 | + // ARM profile |
| 5679 | + // Only do this on ARM and not AArch64 since LLVM aarch64 backend |
| 5680 | + // doesn't support setting profiles. |
| 5681 | + // AFAIK there's currently no 64bit R and M profile either |
| 5682 | + // (v8r and v8m are both 32bit) |
| 5683 | +#if defined(__ARM_ARCH_PROFILE) |
| 5684 | +# if __ARM_ARCH_PROFILE == 'A' |
| 5685 | + HostFeatures["aclass"] = true; |
| 5686 | +# elif __ARM_ARCH_PROFILE == 'R' |
| 5687 | + HostFeatures["rclass"] = true; |
| 5688 | +# elif __ARM_ARCH_PROFILE == 'M' |
| 5689 | + // Thumb |
| 5690 | + HostFeatures["mclass"] = true; |
| 5691 | +# endif |
| 5692 | +#endif |
| 5693 | +#endif // _CPU_ARM_ |
| 5694 | + |
| 5695 | + // On ARM and AArch64, allow using cpu_target to specify a CPU architecture |
| 5696 | + // which is specified in the feature set in LLVM. |
| 5697 | +#if defined(_CPU_ARM_) || defined(_CPU_AARCH64_) |
| 5698 | + // Supported ARM arch names on LLVM 3.8: |
| 5699 | + // armv6, armv6-m, armv6j, armv6k, armv6kz, armv6s-m, armv6t2, |
| 5700 | + // armv7, armv7-a, armv7-m, armv7-r, armv7e-m, armv7k, armv7s, |
| 5701 | + // armv8, armv8-a, armv8.1-a, armv8.2-a |
| 5702 | + // Additional ARM arch names on LLVM 3.9: |
| 5703 | + // armv8-m.base, armv8-m.main |
| 5704 | + // |
| 5705 | + // Supported AArch64 arch names on LLVM 3.8: |
| 5706 | + // armv8.1a, armv8.2a |
| 5707 | + std::string arm_arch = checkARMArchFeature(cpu); |
| 5708 | + if (!arm_arch.empty()) { |
| 5709 | + HostFeatures[arm_arch] = true; |
| 5710 | + cpu = "generic"; |
5606 | 5711 | }
|
| 5712 | +#endif |
5607 | 5713 |
|
5608 | 5714 | SmallVector<std::string,10> attr;
|
5609 | 5715 | for (StringMap<bool>::const_iterator it = HostFeatures.begin(); it != HostFeatures.end(); it++) {
|
@@ -5720,8 +5826,8 @@ extern "C" void jl_init_codegen(void)
|
5720 | 5826 | TheTriple.setEnvironment(Triple::ELF);
|
5721 | 5827 | #endif
|
5722 | 5828 | #endif
|
5723 |
| - std::string TheCPU = strcmp(jl_options.cpu_target,"native") ? jl_options.cpu_target : sys::getHostCPUName(); |
5724 |
| - SmallVector<std::string, 10> targetFeatures = getTargetFeatures( ); |
| 5829 | + std::string TheCPU; |
| 5830 | + SmallVector<std::string, 10> targetFeatures = getTargetFeatures(TheCPU); |
5725 | 5831 | jl_TargetMachine = eb.selectTarget(
|
5726 | 5832 | TheTriple,
|
5727 | 5833 | "",
|
|
0 commit comments