x86_64: -march=native support
Subsystems (12)
PATCH 1/5 x86_64: -march=native support
I'm tired of rebasing it, so...
"-march=native" has been available in userspace for a long time and is trivial to enable in Gentoo:
$ grep -e ^CFLAGS /etc/portage/make.conf CFLAGS="-march=native -O2 -pipe"
Patchset enables kernel compile with "-march=native" and do additional optimizations based on CPU detection. Unfortunately most of the fun is in SSE2/AVX2 instructions and kernel can't use those. But I have ideas for at least BMI2.
This is intended to be an alternative to old school MCORE2 options. Gentoo also ships a patch unrolling all those individual -march= options into kernel config options. This patch should deprecate it.
See the link for more information:
https://www.shlomifish.org/humour/by-others/funroll-loops/Gentoo-is-Rice.html
Patch adds:
* -mgeneral-regs-only
with -march=native all those shiny AVX42-666 instructions may suddenly became available
* small compile time partial CPUID detection,
* detect L1 cache shift at compile time,
* show "-march=native" line in /proc/config.gz,
* bump Kconfig "shell" output buffer to accomodate the option,
* inject individual MARCH_NATIVE options at compile time, see other patches.
Currently only Intel and gcc are supported.
Intel, because I never had and AMD box.
Gcc, because clang emits detailed "march=native" information in a different way, so I need to think how to extract it reliably.
Size benchmarks, my trimmed down kernel:
add/remove: 1/11 grow/shrink: 1856/5598 up/down: 14452/-65830 (-51378) Function old new delta sha_transform 4302 4606 +304 ... udf_write_fi 1907 1023 -884 Total: Before=7814760, After=7763382, chg -0.66%
This is mostly due to memset() un-unrolling.
In general, say, crypto and hash code becomes bigger because all those rotations and shifts become RORX and SHLX instructions and those are 5+ bytes. Older compilers may also emit "REP RET" on generic kernels because AMD, but upon detecting Intel those REP prefixes may go.
Users are advised to enable it and do their own benchmarks to decide if it is worth the hassle.
--- Makefile | 4 ++ arch/x86/Kconfig.cpu | 20 +++++++++ arch/x86/Makefile | 1 + scripts/kconfig/.gitignore | 1 + scripts/kconfig/Makefile | 7 ++- scripts/kconfig/cpuid.c | 85 ++++++++++++++++++++++++++++++++++++ scripts/kconfig/preprocess.c | 2 +- scripts/march-native.sh | 66 ++++++++++++++++++++++++++++ 8 files changed, 184 insertions(+), 2 deletions(-) create mode 100644 scripts/kconfig/cpuid.c create mode 100755 scripts/march-native.sh
Makefile +4 -0
@@ -606,6 +606,10 @@ ifeq ($(dot-config),1) include include/config/auto.conf endif +ifdef CONFIG_MARCH_NATIVE +KBUILD_CFLAGS += -march=native +endif + ifeq ($(KBUILD_EXTMOD),) # Objects we will link into vmlinux / subdirs we need to visit init-y := init/
arch/x86/Kconfig.cpu +20 -0
@@ -287,8 +287,26 @@ config GENERIC_CPU Generic x86-64 CPU. Run equally well on all x86-64 CPUs. +config MARCH_NATIVE + bool "-march=native" + depends on X86_64 && CC_IS_GCC + ---help--- + Compile with -march=native. + + Optimise for the machine where compilation is done at. Resulting + kernel and modules will not run reliably on a different machine + unless exactly identical CPUs are used. + + Select only if you're self-compiling kernels and never share + the binaries. If unsure, select "Generic x86_64". + endchoice +config MARCH_NATIVE_CC_FLAGS + string + depends on MARCH_NATIVE && CC_IS_GCC + default "$(shell,$(CC) -march=native -v -E -x c /dev/null 2>&1 | sed -ne '/^COLLECT_GCC_OPTIONS=/{n;p}' | awk '{$1=$1};1')" + config X86_GENERIC bool "Generic x86 support" depends on X86_32
@@ -307,6 +325,7 @@ config X86_INTERNODE_CACHE_SHIFT int default "12" if X86_VSMP default X86_L1_CACHE_SHIFT + depends on !MARCH_NATIVE config X86_L1_CACHE_SHIFT int
@@ -314,6 +333,7 @@ config X86_L1_CACHE_SHIFT default "6" if MK7 || MK8 || MPENTIUMM || MCORE2 || MATOM || MVIAC7 || X86_GENERIC || GENERIC_CPU default "4" if MELAN || M486 || MGEODEGX1 default "5" if MWINCHIP3D || MWINCHIPC6 || MCRUSOE || MEFFICEON || MCYRIXIII || MK6 || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || M586 || MVIAC3_2 || MGEODE_LX + depends on !MARCH_NATIVE config X86_F00F_BUG def_bool y
arch/x86/Makefile +1 -0
@@ -59,6 +59,7 @@ endif # KBUILD_CFLAGS += -mno-sse -mno-mmx -mno-sse2 -mno-3dnow KBUILD_CFLAGS += $(call cc-option,-mno-avx,) +KBUILD_CFLAGS += $(call cc-option,-mgeneral-regs-only) ifeq ($(CONFIG_X86_32),y) BITS := 32
scripts/kconfig/.gitignore +1 -0
@@ -8,6 +8,7 @@ # configuration programs # conf +cpuid mconf nconf qconf
scripts/kconfig/Makefile +6 -1
@@ -69,8 +69,9 @@ simple-targets := oldconfig allnoconfig allyesconfig allmodconfig \ alldefconfig randconfig listnewconfig olddefconfig syncconfig PHONY += $(simple-targets) -$(simple-targets): $(obj)/conf +$(simple-targets): $(obj)/conf $(obj)/cpuid $< $(silent) --$@ $(Kconfig) + $(Q)$(srctree)/scripts/march-native.sh $(CC) $(obj)/cpuid PHONY += savedefconfig defconfig
@@ -150,6 +151,10 @@ $(obj)/lexer.lex.o: $(obj)/parser.tab.h HOSTCFLAGS_lexer.lex.o := -I $(srctree)/$(src) HOSTCFLAGS_parser.tab.o := -I $(srctree)/$(src) +# cpuid: -march=native, CONFIG_MARCH_NATIVE_* detection +hostprogs-y += cpuid +cpuid-objs := cpuid.o + # conf: Used for defconfig, oldconfig and related targets hostprogs-y += conf conf-objs := conf.o $(common-objs)
scripts/kconfig/cpuid.c new file +85 -0
85 lines not on this page · raw message
scripts/kconfig/preprocess.c +1 -1
@@ -141,7 +141,7 @@ static char *do_lineno(int argc, char *argv[])static char *do_shell (int argc,char *argv[]) {FILE *p; -char buf[256 ]; +char buf[2048 ];char *cmd;size_t nread;int i;
scripts/march-native.sh new file +66 -0
66 lines not on this page · raw message
Signature · 1 line
2.21.0
PATCH 2/5 x86_64, -march=native: POPCNT support
Detect POPCNT instruction support and inline hweigth*() functions if it is supported by CPU.
Detect POPCNT at boot time and conditionally refuse to boot.
--- arch/x86/include/asm/arch_hweight.h | 24 +++++++++++++++++++ arch/x86/include/asm/segment.h | 1 + arch/x86/kernel/verify_cpu.S | 8 +++++++ arch/x86/lib/Makefile | 5 +++- .../drm/i915/display/intel_display_power.c | 2 +- drivers/misc/sgi-gru/grumain.c | 2 +- fs/btrfs/tree-checker.c | 4 ++-- include/linux/bitops.h | 2 ++ lib/Makefile | 2 ++ scripts/kconfig/cpuid.c | 7 ++++++ scripts/march-native.sh | 2 ++ 11 files changed, 54 insertions(+), 5 deletions(-)
arch/x86/include/asm/arch_hweight.h +24 -0
@@ -2,6 +2,28 @@#ifndef _ASM_X86_HWEIGHT_H#define _ASM_X86_HWEIGHT_H +#ifdef CONFIG_MARCH_NATIVE_POPCNT +static inline unsigned int __arch_hweight64 (uint64_t x) +{ +return __builtin_popcountll (x); +} + +static inline unsigned int __arch_hweight32 (uint32_t x) +{ +return __builtin_popcount (x); +} + +static inline unsigned int __arch_hweight16 (uint16_t x) +{ +return __builtin_popcount (x); +} + +static inline unsigned int __arch_hweight8 (uint8_t x) +{ +return __builtin_popcount (x); +} +#else +#include <asm/cpufeatures.h> #ifdef CONFIG_64BIT
@@ -53,3 +75,5 @@ static __always_inline unsigned long __arch_hweight64(__u64 w)#endif /* CONFIG_X86_32 */ #endif + +#endif
arch/x86/include/asm/segment.h +1 -0
@@ -4,6 +4,7 @@#include <linux/const.h> #include <asm/alternative.h> +#include <asm/cpufeatures.h> /* * Constructor for a conventional segment GDT (or LDT) entry.
arch/x86/kernel/verify_cpu.S +8 -0
@@ -134,6 +134,14 @@ ENTRY(verify_cpu) movl $1,%eax ret .Lverify_cpu_sse_ok: + +#ifdef CONFIG_MARCH_NATIVE_POPCNT + mov $1, %eax + cpuid + bt $23, %ecx + jnc .Lverify_cpu_no_longmode +#endif + popf # Restore caller passed flags xorl %eax, %eax ret
arch/x86/lib/Makefile +4 -1
@@ -40,7 +40,10 @@ lib-$(CONFIG_RANDOMIZE_BASE) += kaslr.o lib-$(CONFIG_FUNCTION_ERROR_INJECTION) += error-inject.o lib-$(CONFIG_RETPOLINE) += retpoline.o -obj-y += msr.o msr-reg.o msr-reg-export.o hweight.o +obj-y += msr.o msr-reg.o msr-reg-export.o +ifneq ($(CONFIG_MARCH_NATIVE_POPCNT),y) + obj-y += hweight.o +endif obj-y += iomem.o ifeq ($(CONFIG_X86_32),y)
drivers/gpu/drm/i915/display/intel_display_power.c +1 -1
@@ -1570,7 +1570,7 @@ static void print_power_domains(struct i915_power_domains *power_domains, {enum intel_display_power_domain domain; -DRM_DEBUG_DRIVER ("%s (%lu):\n" , prefix,hweight64 (mask)); +DRM_DEBUG_DRIVER ("%s (%u):\n" , prefix,hweight64 (mask));for_each_power_domain (domain, mask) DRM_DEBUG_DRIVER("%s use_count %d\n", intel_display_power_domain_str(domain),
drivers/misc/sgi-gru/grumain.c +1 -1
@@ -833,7 +833,7 @@ void gru_steal_context(struct gru_thread_state *gts) }gru_dbg (grudev,"stole gid %d, ctxnum %d from gts %p. Need cb %d, ds %d;" -" avail cb %ld, ds %ld\n" , +" avail cb %u, ds %u\n" , gru->gs_gid, ctxnum, ngts, cbr, dsr,hweight64 (gru->gs_cbr_map),hweight64 (gru->gs_dsr_map)); }
fs/btrfs/tree-checker.c +2 -2
@@ -478,7 +478,7 @@ static int check_block_group_item(struct extent_buffer *leaf, flags =btrfs_block_group_flags (&bgi);if (hweight64 (flags &BTRFS_BLOCK_GROUP_PROFILE_MASK ) >1 ) {block_group_err (leaf, slot, -"invalid profile flags, have 0x%llx (%lu bits set) expect no more than 1 bit set" , +"invalid profile flags, have 0x%llx (%u bits set) expect no more than 1 bit set" , flags &BTRFS_BLOCK_GROUP_PROFILE_MASK ,hweight64 (flags &BTRFS_BLOCK_GROUP_PROFILE_MASK ));return -EUCLEAN ;
@@ -491,7 +491,7 @@ static int check_block_group_item(struct extent_buffer *leaf, type != (BTRFS_BLOCK_GROUP_METADATA | BTRFS_BLOCK_GROUP_DATA)) { block_group_err(leaf, slot, -"invalid type, have 0x%llx (%lu bits set) expect either 0x%llx, 0x%llx, 0x%llx or 0x%llx", +"invalid type, have 0x%llx (%u bits set) expect either 0x%llx, 0x%llx, 0x%llx or 0x%llx", type, hweight64(type), BTRFS_BLOCK_GROUP_DATA, BTRFS_BLOCK_GROUP_METADATA, BTRFS_BLOCK_GROUP_SYSTEM,
include/linux/bitops.h +2 -0
@@ -7,10 +7,12 @@#define BITS_PER_TYPE (type) (sizeof(type) * BITS_PER_BYTE)#define BITS_TO_LONGS (nr) DIV_ROUND_UP(nr, BITS_PER_TYPE(long)) +#ifndef CONFIG_MARCH_NATIVE_POPCNT extern unsigned int __sw_hweight8 (unsigned int w);extern unsigned int __sw_hweight16 (unsigned int w);extern unsigned int __sw_hweight32 (unsigned int w);extern unsigned long __sw_hweight64 (__u64 w); +#endif /* * Include this here because some architectures need generic_ffs/fls in
lib/Makefile +2 -0
@@ -114,7 +114,9 @@ obj-$(CONFIG_DEBUG_LOCKING_API_SELFTESTS) += locking-selftest.o obj-y += logic_pio.o +ifneq ($(CONFIG_MARCH_NATIVE_POPCNT),y) obj-$(CONFIG_GENERIC_HWEIGHT) += hweight.o +endif obj-$(CONFIG_BTREE) += btree.o obj-$(CONFIG_INTERVAL_TREE) += interval_tree.o
scripts/kconfig/cpuid.c +7 -0
@@ -43,6 +43,8 @@ static inline void cpuid2(uint32_t eax0, uint32_t ecx0, uint32_t *eax, uint32_t ); } +static bool popcnt = false; +static uint32_t eax0_max;static void intel (void )
@@ -52,6 +54,10 @@ static void intel(void)if (eax0_max >=1 ) {cpuid (1 , &eax, &ecx, &edx, &ebx);// printf("%08x %08x %08x %08x\n", eax, ecx, edx, ebx); + +if (ecx & (1 <<23 )) { + popcnt = true; + } } }
@@ -72,6 +78,7 @@ int main(int argc, char *argv[]) }#define _ (x) if (streq(opt, #x)) return x ? EXIT_SUCCESS : EXIT_FAILURE +_ (popcnt);#undef _return EXIT_FAILURE ;
scripts/march-native.sh +2 -0
@@ -41,6 +41,8 @@ COLLECT_GCC_OPTIONS=$( ) echo "-march=native: $COLLECT_GCC_OPTIONS" +"$CPUID" popcnt && option "CONFIG_MARCH_NATIVE_POPCNT" + for i in $COLLECT_GCC_OPTIONS; do case $i in */cc1|-E|-quiet|-v|/dev/null|--param|-fstack-protector*)
Signature · 1 line
2.21.0
Re: [PATCH 2/5] x86_64, -march=native: POPCNT support
Quoted 6 lines · Alexey Dobriyan
Detect POPCNT instruction support and inline hweigth*() functions if it is supported by CPU.
Detect POPCNT at boot time and conditionally refuse to boot.
Signed-off-by Alexey Dobriyan <[email protected]>
Quoted 13 lines
--- arch/x86/include/asm/arch_hweight.h | 24 +++++++++++++++++++ arch/x86/include/asm/segment.h | 1 + arch/x86/kernel/verify_cpu.S | 8 +++++++ arch/x86/lib/Makefile | 5 +++- .../drm/i915/display/intel_display_power.c | 2 +- drivers/misc/sgi-gru/grumain.c | 2 +- fs/btrfs/tree-checker.c | 4 ++-- include/linux/bitops.h | 2 ++ lib/Makefile | 2 ++ scripts/kconfig/cpuid.c | 7 ++++++ scripts/march-native.sh | 2 ++ 11 files changed, 54 insertions(+), 5 deletions(-)
*WHY* ?
AFAICT this just adds lines and complexity and wins aboslutely nothing.
Re: [PATCH 2/5] x86_64, -march=native: POPCNT support
Quoted 21 lines · Peter Zijlstra
Quoted 6 lines · Alexey Dobriyan
Detect POPCNT instruction support and inline hweigth*() functions if it is supported by CPU.
Detect POPCNT at boot time and conditionally refuse to boot.
Signed-off-by Alexey Dobriyan <[email protected]>Quoted 13 lines
--- arch/x86/include/asm/arch_hweight.h | 24 +++++++++++++++++++ arch/x86/include/asm/segment.h | 1 + arch/x86/kernel/verify_cpu.S | 8 +++++++ arch/x86/lib/Makefile | 5 +++- .../drm/i915/display/intel_display_power.c | 2 +- drivers/misc/sgi-gru/grumain.c | 2 +- fs/btrfs/tree-checker.c | 4 ++-- include/linux/bitops.h | 2 ++ lib/Makefile | 2 ++ scripts/kconfig/cpuid.c | 7 ++++++ scripts/march-native.sh | 2 ++ 11 files changed, 54 insertions(+), 5 deletions(-)
Quoted 3 lines
*WHY* ?
AFAICT this just adds lines and complexity and wins aboslutely nothing.
If CPU is know to have POPCNT, it doesn't make sense to go through RDI. Additionally some CPUs (still?) have fake dependency on the destination, so "popcnt rax, rdi" is suboptimal.
Re: [PATCH 2/5] x86_64, -march=native: POPCNT support
Quoted 22 lines · Alexey Dobriyan
Quoted 21 lines · Peter Zijlstra
Quoted 19 lines · Alexey Dobriyan
Detect POPCNT instruction support and inline hweigth*() functions if it is supported by CPU.
Detect POPCNT at boot time and conditionally refuse to boot.
Signed-off-by Alexey Dobriyan <[email protected]>--- arch/x86/include/asm/arch_hweight.h | 24 +++++++++++++++++++ arch/x86/include/asm/segment.h | 1 + arch/x86/kernel/verify_cpu.S | 8 +++++++ arch/x86/lib/Makefile | 5 +++- .../drm/i915/display/intel_display_power.c | 2 +- drivers/misc/sgi-gru/grumain.c | 2 +- fs/btrfs/tree-checker.c | 4 ++-- include/linux/bitops.h | 2 ++ lib/Makefile | 2 ++ scripts/kconfig/cpuid.c | 7 ++++++ scripts/march-native.sh | 2 ++ 11 files changed, 54 insertions(+), 5 deletions(-)
Quoted 7 lines
Quoted 3 lines
*WHY* ?
AFAICT this just adds lines and complexity and wins aboslutely nothing.
If CPU is know to have POPCNT, it doesn't make sense to go through RDI. Additionally some CPUs (still?) have fake dependency on the destination, so "popcnt rax, rdi" is suboptimal.
More general argument is that if -march=native is accepted, compiler will generate new instructions which will throw #UD on CPUs which aren't capable, so it doesn't make sense to _not_ go deeper and use all the knowledge about current CPU.
Re: [PATCH 2/5] x86_64, -march=native: POPCNT support
In reply to Alexey DobriyanQuoted 22 lines · Alexey Dobriyan
Quoted 21 lines · Peter Zijlstra
Quoted 19 lines · Alexey Dobriyan
Detect POPCNT instruction support and inline hweigth*() functions if it is supported by CPU.
Detect POPCNT at boot time and conditionally refuse to boot.
Signed-off-by Alexey Dobriyan <[email protected]>--- arch/x86/include/asm/arch_hweight.h | 24 +++++++++++++++++++ arch/x86/include/asm/segment.h | 1 + arch/x86/kernel/verify_cpu.S | 8 +++++++ arch/x86/lib/Makefile | 5 +++- .../drm/i915/display/intel_display_power.c | 2 +- drivers/misc/sgi-gru/grumain.c | 2 +- fs/btrfs/tree-checker.c | 4 ++-- include/linux/bitops.h | 2 ++ lib/Makefile | 2 ++ scripts/kconfig/cpuid.c | 7 ++++++ scripts/march-native.sh | 2 ++ 11 files changed, 54 insertions(+), 5 deletions(-)
Quoted 7 lines
Quoted 3 lines
*WHY* ?
AFAICT this just adds lines and complexity and wins aboslutely nothing.
If CPU is know to have POPCNT, it doesn't make sense to go through RDI. Additionally some CPUs (still?) have fake dependency on the destination, so "popcnt rax, rdi" is suboptimal.
You completely forgot to mention any of that in your Changelog, also I doubt you can find code where this makes a measurable difference. IOW, I still doubt it makes any kind of sense.
Re: [PATCH 2/5] x86_64, -march=native: POPCNT support
Quoted 27 lines · Peter Zijlstra
Quoted 26 lines · Alexey Dobriyan
Quoted 24 lines · Peter Zijlstra
Quoted 6 lines · Alexey Dobriyan
Detect POPCNT instruction support and inline hweigth*() functions if it is supported by CPU.
Detect POPCNT at boot time and conditionally refuse to boot.
Signed-off-by Alexey Dobriyan <[email protected]>Quoted 13 lines
--- arch/x86/include/asm/arch_hweight.h | 24 +++++++++++++++++++ arch/x86/include/asm/segment.h | 1 + arch/x86/kernel/verify_cpu.S | 8 +++++++ arch/x86/lib/Makefile | 5 +++- .../drm/i915/display/intel_display_power.c | 2 +- drivers/misc/sgi-gru/grumain.c | 2 +- fs/btrfs/tree-checker.c | 4 ++-- include/linux/bitops.h | 2 ++ lib/Makefile | 2 ++ scripts/kconfig/cpuid.c | 7 ++++++ scripts/march-native.sh | 2 ++ 11 files changed, 54 insertions(+), 5 deletions(-)*WHY* ?
AFAICT this just adds lines and complexity and wins aboslutely nothing.
Quoted 7 lines
Quoted 3 lines
If CPU is know to have POPCNT, it doesn't make sense to go through RDI. Additionally some CPUs (still?) have fake dependency on the destination, so "popcnt rax, rdi" is suboptimal.
You completely forgot to mention any of that in your Changelog, also I doubt you can find code where this makes a measurable difference. IOW, I still doubt it makes any kind of sense.
It saves some space, although not much. gcc likes to use 64-bit version even where 32-bit version should suffice.
Regardless I found some problems with POPCNT patch, so hold off the series.
PATCH 3/5 x86_64, -march=native: REP MOVSB support
In reply to Alexey DobriyanDetect fast REP MOVSB support and use it for page copying.
Inline copy_page(), this saves alternative entry and a function call overhead which should hopefully improve code generation.
--- Makefile | 3 +++ arch/x86/include/asm/page_64.h | 13 +++++++++++++ arch/x86/kernel/relocate_kernel_64.S | 15 +++++++++++++++ arch/x86/kernel/verify_cpu.S | 12 ++++++++++++ arch/x86/lib/Makefile | 5 ++++- arch/x86/lib/memcpy_64.S | 13 +++++++++++++ arch/x86/platform/pvh/head.S | 4 ++++ scripts/kconfig/cpuid.c | 9 +++++++++ scripts/march-native.sh | 1 + 9 files changed, 74 insertions(+), 1 deletion(-)
Makefile +3 -0
@@ -609,6 +609,9 @@ endif ifdef CONFIG_MARCH_NATIVE KBUILD_CFLAGS += -march=native endif +ifdef CONFIG_MARCH_NATIVE_REP_MOVSB +KBUILD_CFLAGS += -mmemcpy-strategy=rep_byte:-1:align,rep_byte:-1:noalign +endif ifeq ($(KBUILD_EXTMOD),) # Objects we will link into vmlinux / subdirs we need to visit
arch/x86/include/asm/page_64.h +13 -0
@@ -54,7 +54,20 @@ static inline void clear_page(void *page) : "cc", "memory", "rax", "rcx"); } +#ifdef CONFIG_MARCH_NATIVE_REP_MOVSB +static __always_inline void copy_page(void *to, void *from) +{ +uint32_t len =PAGE_SIZE ; + asmvolatile ( +"rep movsb" + :"+D" (to),"+S" (from),"+c" (len) + : + :"memory" + ); +} +#else void copy_page (void *to,void *from); +#endif #endif /* !__ASSEMBLY__ */
arch/x86/kernel/relocate_kernel_64.S +15 -0
@@ -266,18 +266,33 @@ swap_pages: movq %rsi, %rax movq %r10, %rdi +#ifdef CONFIG_MARCH_NATIVE_REP_MOVSB + mov $4096, %ecx + rep movsb +#else movl $512, %ecx rep ; movsq +#endif movq %rax, %rdi movq %rdx, %rsi +#ifdef CONFIG_MARCH_NATIVE_REP_MOVSB + mov $4096, %ecx + rep movsb +#else movl $512, %ecx rep ; movsq +#endif movq %rdx, %rdi movq %r10, %rsi +#ifdef CONFIG_MARCH_NATIVE_REP_MOVSB + mov $4096, %ecx + rep movsb +#else movl $512, %ecx rep ; movsq +#endif lea PAGE_SIZE(%rax), %rsi jmp 0b
arch/x86/kernel/verify_cpu.S +12 -0
@@ -142,6 +142,18 @@ ENTRY(verify_cpu) jnc .Lverify_cpu_no_longmode #endif +#ifdef CONFIG_MARCH_NATIVE_REP_MOVSB + xor %eax, %eax + cpuid + cmp $7, %eax + jb .Lverify_cpu_no_longmode + mov $7, %eax + xor %ecx, %ecx + cpuid + bt $9, %ebx + jnc .Lverify_cpu_no_longmode +#endif + popf # Restore caller passed flags xorl %eax, %eax ret
arch/x86/lib/Makefile +4 -1
@@ -59,7 +59,10 @@ endif else obj-y += iomap_copy_64.o lib-y += csum-partial_64.o csum-copy_64.o csum-wrappers_64.o - lib-y += clear_page_64.o copy_page_64.o + lib-y += clear_page_64.o +ifneq ($(CONFIG_MARCH_NATIVE_REP_MOVSB),y) + lib-y += copy_page_64.o +endif lib-y += memmove_64.o memset_64.o lib-y += copy_user_64.o lib-y += cmpxchg16b_emu.o
arch/x86/lib/memcpy_64.S +13 -0
@@ -17,6 +17,18 @@ .weak memcpy +#ifdef CONFIG_MARCH_NATIVE_REP_MOVSB +ENTRY(__memcpy) +ENTRY(memcpy) + mov %rdi, %rax + mov %rdx, %rcx + rep movsb + ret +ENDPROC(memcpy) +ENDPROC(__memcpy) +EXPORT_SYMBOL(memcpy) +EXPORT_SYMBOL(__memcpy) +#else /* * memcpy - Copy a memory block. *
@@ -183,6 +195,7 @@ ENTRY(memcpy_orig) .Lend: retq ENDPROC(memcpy_orig) +#endif #ifndef CONFIG_UML
arch/x86/platform/pvh/head.S +4 -0
@@ -64,9 +64,13 @@ ENTRY(pvh_start_xen) mov $_pa(pvh_start_info), %edi mov %ebx, %esi mov _pa(pvh_start_info_sz), %ecx +#ifdef CONFIG_MARCH_NATIVE_REP_MOVSB + rep movsb +#else shr $2,%ecx rep movsl +#endif mov $_pa(early_stack_end), %esp
scripts/kconfig/cpuid.c +9 -0
@@ -44,6 +44,7 @@ static inline void cpuid2(uint32_t eax0, uint32_t ecx0, uint32_t *eax, uint32_t }static bool popcnt = false; +static bool rep_movsb = false;static uint32_t eax0_max;
@@ -59,6 +60,13 @@ static void intel(void) popcnt = true; } } +if (eax0_max >=7 ) { +cpuid2 (7 ,0 , &eax, &ecx, &edx, &ebx); +// printf("%08x %08x %08x %08x\n", eax, ecx, edx, ebx); + +if (ebx & (1 <<9 )) + rep_movsb = true; + } }int main (int argc,char *argv[])
@@ -79,6 +87,7 @@ int main(int argc, char *argv[])#define _ (x) if (streq(opt, #x)) return x ? EXIT_SUCCESS : EXIT_FAILURE_ (popcnt); +_ (rep_movsb);#undef _return EXIT_FAILURE ;
scripts/march-native.sh +1 -0
@@ -42,6 +42,7 @@ COLLECT_GCC_OPTIONS=$( echo "-march=native: $COLLECT_GCC_OPTIONS" "$CPUID" popcnt && option "CONFIG_MARCH_NATIVE_POPCNT" +"$CPUID" rep_movsb && option "CONFIG_MARCH_NATIVE_REP_MOVSB" for i in $COLLECT_GCC_OPTIONS; do case $i in
Signature · 1 line
2.21.0
PATCH 4/5 x86_64, -march=native: REP STOSB support
In reply to Alexey DobriyanUse REP STOSB everywhere if CPU advertises fast REP STOSB.
Gcc LOVES to unroll memset(), using -mmemset-strategy saves terabytes of .text.
--- Makefile | 3 +++ arch/x86/boot/compressed/head_64.S | 4 ++++ arch/x86/crypto/sha1_ssse3_asm.S | 7 ++++++- arch/x86/include/asm/page_64.h | 13 +++++++++++++ arch/x86/kernel/verify_cpu.S | 2 +- arch/x86/lib/Makefile | 2 ++ arch/x86/lib/memset_64.S | 15 +++++++++++++++ arch/x86/lib/usercopy_64.c | 16 +++++++++++++++- scripts/kconfig/cpuid.c | 6 +++++- scripts/march-native.sh | 1 + 10 files changed, 65 insertions(+), 4 deletions(-)
Makefile +3 -0
@@ -612,6 +612,9 @@ endif ifdef CONFIG_MARCH_NATIVE_REP_MOVSB KBUILD_CFLAGS += -mmemcpy-strategy=rep_byte:-1:align,rep_byte:-1:noalign endif +ifdef CONFIG_MARCH_NATIVE_REP_STOSB +KBUILD_CFLAGS += -mmemset-strategy=rep_byte:-1:align,rep_byte:-1:noalign +endif ifeq ($(KBUILD_EXTMOD),) # Objects we will link into vmlinux / subdirs we need to visit
arch/x86/boot/compressed/head_64.S +4 -0
@@ -520,8 +520,12 @@ relocated: leaq _bss(%rip), %rdi leaq _ebss(%rip), %rcx subq %rdi, %rcx +#ifdef CONFIG_MARCH_NATIVE_REP_STOSB + rep stosb +#else shrq $3, %rcx rep stosq +#endif /* * Do the extraction, and jump to the new kernel..
arch/x86/crypto/sha1_ssse3_asm.S +6 -1
@@ -90,10 +90,15 @@ SHA1_PIPELINED_MAIN_BODY # cleanup workspace - mov $8, %ecx mov %rsp, %rdi xor %eax, %eax +#ifdef CONFIG_MARCH_NATIVE_REP_STOSB + mov $64, %ecx + rep stosb +#else + mov $8, %ecx rep stosq +#endif mov %rbp, %rsp # deallocate workspace pop %rbp
arch/x86/include/asm/page_64.h +13 -0
@@ -40,6 +40,18 @@ extern unsigned long __phys_addr_symbol(unsigned long);#define pfn_valid (pfn) ((pfn) < max_pfn)#endif +#ifdef CONFIG_MARCH_NATIVE_REP_STOSB +static __always_inline void clear_page(void *page) +{ +uint32_t len =PAGE_SIZE ; + asmvolatile ( +"rep stosb" + :"+D" (page),"+c" (len) + :"a" (0 ) + :"memory" + ); +} +#else void clear_page_orig (void *page);void clear_page_rep (void *page);void clear_page_erms (void *page);
@@ -53,6 +65,7 @@ static inline void clear_page(void *page) "0" (page) : "cc", "memory", "rax", "rcx"); } +#endif #ifdef CONFIG_MARCH_NATIVE_REP_MOVSB static __always_inline void copy_page(void *to, void *from)
arch/x86/kernel/verify_cpu.S +1 -1
@@ -142,7 +142,7 @@ ENTRY(verify_cpu) jnc .Lverify_cpu_no_longmode #endif -#ifdef CONFIG_MARCH_NATIVE_REP_MOVSB +#if defined(CONFIG_MARCH_NATIVE_REP_MOVSB) || defined(CONFIG_MARCH_NATIVE_REP_STOSB) xor %eax, %eax cpuid cmp $7, %eax
arch/x86/lib/Makefile +2 -0
@@ -59,7 +59,9 @@ endif else obj-y += iomap_copy_64.o lib-y += csum-partial_64.o csum-copy_64.o csum-wrappers_64.o +ifneq ($(CONFIG_MARCH_NATIVE_REP_STOSB),y) lib-y += clear_page_64.o +endif ifneq ($(CONFIG_MARCH_NATIVE_REP_MOVSB),y) lib-y += copy_page_64.o endif
arch/x86/lib/memset_64.S +15 -0
@@ -8,6 +8,20 @@ .weak memset +#ifdef CONFIG_MARCH_NATIVE_REP_STOSB +ENTRY(memset) +ENTRY(__memset) + mov %esi, %eax + mov %rdi, %rsi + mov %rdx, %rcx + rep stosb + mov %rsi, %rax + ret +ENDPROC(memset) +ENDPROC(__memset) +EXPORT_SYMBOL(memset) +EXPORT_SYMBOL(__memset) +#else /* * ISO C memset - set a memory block to a byte value. This function uses fast * string to get better performance than the original function. The code is
@@ -140,3 +154,4 @@ ENTRY(memset_orig) jmp .Lafter_bad_alignment .Lfinal: ENDPROC(memset_orig) +#endif
arch/x86/lib/usercopy_64.c +15 -1
@@ -16,11 +16,23 @@unsigned long __clear_user (void __user *addr,unsigned long size) { -long __d0;might_fault ();/* no memory constraint because it doesn't change any memory gcc knows about */ stac (); + +#ifdef CONFIG_MARCH_NATIVE_REP_STOSB + asmvolatile ( +"0: rep stosb\n" +"1:\n" + _ASM_EXTABLE(0b,1b) + : "+D" (addr), "+c" (size) + : "a" (0) + : "memory" + ); +#else + { +long __d0; asmvolatile (" testq %[size8],%[size8]\n" " jz 4f\n"
@@ -42,6 +54,8 @@ unsigned long __clear_user(void __user *addr, unsigned long size)_ASM_EXTABLE_UA (1b ,2b ) : [size8] "=&c"(size), [dst] "=&D" (__d0) : [size1] "r"(size & 7), "[size8]" (size / 8), "[dst]"(addr)); + } +#endif clac ();return size; }
scripts/kconfig/cpuid.c +5 -1
@@ -45,6 +45,7 @@ static inline void cpuid2(uint32_t eax0, uint32_t ecx0, uint32_t *eax, uint32_tstatic bool popcnt = false;static bool rep_movsb = false; +static bool rep_stosb = false;static uint32_t eax0_max;
@@ -64,8 +65,10 @@ static void intel(void)cpuid2 (7 ,0 , &eax, &ecx, &edx, &ebx);// printf("%08x %08x %08x %08x\n", eax, ecx, edx, ebx); -if (ebx & (1 <<9 )) +if (ebx & (1 <<9 )) { rep_movsb = true; + rep_stosb = true; + } } }
@@ -88,6 +91,7 @@ int main(int argc, char *argv[])#define _ (x) if (streq(opt, #x)) return x ? EXIT_SUCCESS : EXIT_FAILURE_ (popcnt);_ (rep_movsb); +_ (rep_stosb);#undef _return EXIT_FAILURE ;
scripts/march-native.sh +1 -0
@@ -43,6 +43,7 @@ echo "-march=native: $COLLECT_GCC_OPTIONS" "$CPUID" popcnt && option "CONFIG_MARCH_NATIVE_POPCNT" "$CPUID" rep_movsb && option "CONFIG_MARCH_NATIVE_REP_MOVSB" +"$CPUID" rep_stosb && option "CONFIG_MARCH_NATIVE_REP_STOSB" for i in $COLLECT_GCC_OPTIONS; do case $i in
Signature · 1 line
2.21.0
PATCH 5/5 x86_64, -march=native: MOVBE support
In reply to Alexey DobriyanUse MOVBE if it is available.
Internally MOVBE probably translates to MOV+BSWAP anyway, but who knows.
Do it because it is easy to do...
--- arch/x86/crypto/des3_ede-asm_64.S | 28 ++++++++++++++++++++++++++++ arch/x86/kernel/verify_cpu.S | 7 +++++++ scripts/kconfig/cpuid.c | 5 +++++ scripts/march-native.sh | 1 + 4 files changed, 41 insertions(+)
arch/x86/crypto/des3_ede-asm_64.S +28 -0
@@ -150,6 +150,15 @@ #define dummy2(a, b) /*_*/ +#ifdef CONFIG_MARCH_NATIVE_MOVBE +#define read_block(io, left, right) \ + movbe (io), left##d; \ + movbe 4(io), right##d; + +#define write_block(io, left, right) \ + movbe left##d, (io); \ + movbe right##d, 4(io); +#else #define read_block(io, left, right) \ movl (io), left##d; \ movl 4(io), right##d; \
@@ -161,6 +170,7 @@ bswapl right##d; \ movl left##d, (io); \ movl right##d, 4(io); +#endif ENTRY(des3_ede_x86_64_crypt_blk) /* input:
@@ -434,6 +444,14 @@ ENTRY(des3_ede_x86_64_crypt_blk_3way) pushq %rsi /* dst */ /* load input */ +#ifdef CONFIG_MARCH_NATIVE_MOVBE + movbe 0 * 4(%rdx), RL0d; + movbe 1 * 4(%rdx), RR0d; + movbe 2 * 4(%rdx), RL1d; + movbe 3 * 4(%rdx), RR1d; + movbe 4 * 4(%rdx), RL2d; + movbe 5 * 4(%rdx), RR2d; +#else movl 0 * 4(%rdx), RL0d; movl 1 * 4(%rdx), RR0d; movl 2 * 4(%rdx), RL1d;
@@ -447,6 +465,7 @@ ENTRY(des3_ede_x86_64_crypt_blk_3way) bswapl RR1d; bswapl RL2d; bswapl RR2d; +#endif initial_permutation3(RL, RR);
@@ -507,6 +526,14 @@ ENTRY(des3_ede_x86_64_crypt_blk_3way) final_permutation3(RR, RL); +#ifdef CONFIG_MARCH_NATIVE_MOVBE + movbe RR0d, 0 * 4(%rsi); + movbe RL0d, 1 * 4(%rsi); + movbe RR1d, 2 * 4(%rsi); + movbe RL1d, 3 * 4(%rsi); + movbe RR2d, 4 * 4(%rsi); + movbe RL2d, 5 * 4(%rsi); +#else bswapl RR0d; bswapl RL0d; bswapl RR1d;
@@ -521,6 +548,7 @@ ENTRY(des3_ede_x86_64_crypt_blk_3way) movl RL1d, 3 * 4(%rsi); movl RR2d, 4 * 4(%rsi); movl RL2d, 5 * 4(%rsi); +#endif popq %r15; popq %r14;
arch/x86/kernel/verify_cpu.S +7 -0
@@ -142,6 +142,13 @@ ENTRY(verify_cpu) jnc .Lverify_cpu_no_longmode #endif +#ifdef CONFIG_MARCH_NATIVE_MOVBE + mov $1, %eax + cpuid + bt $22, %ecx + jnc .Lverify_cpu_no_longmode +#endif + #if defined(CONFIG_MARCH_NATIVE_REP_MOVSB) || defined(CONFIG_MARCH_NATIVE_REP_STOSB) xor %eax, %eax cpuid
scripts/kconfig/cpuid.c +5 -0
@@ -43,6 +43,7 @@ static inline void cpuid2(uint32_t eax0, uint32_t ecx0, uint32_t *eax, uint32_t ); } +static bool movbe = false;static bool popcnt = false;static bool rep_movsb = false;static bool rep_stosb = false;
@@ -57,6 +58,9 @@ static void intel(void)cpuid (1 , &eax, &ecx, &edx, &ebx);// printf("%08x %08x %08x %08x\n", eax, ecx, edx, ebx); +if (ecx & (1 <<22 )) { + movbe = true; + }if (ecx & (1 <<23 )) { popcnt = true; }
@@ -89,6 +93,7 @@ int main(int argc, char *argv[]) }#define _ (x) if (streq(opt, #x)) return x ? EXIT_SUCCESS : EXIT_FAILURE +_ (movbe);_ (popcnt);_ (rep_movsb);_ (rep_stosb);
scripts/march-native.sh +1 -0
@@ -41,6 +41,7 @@ COLLECT_GCC_OPTIONS=$( ) echo "-march=native: $COLLECT_GCC_OPTIONS" +"$CPUID" movbe && option "CONFIG_MARCH_NATIVE_MOVBE" "$CPUID" popcnt && option "CONFIG_MARCH_NATIVE_POPCNT" "$CPUID" rep_movsb && option "CONFIG_MARCH_NATIVE_REP_MOVSB" "$CPUID" rep_stosb && option "CONFIG_MARCH_NATIVE_REP_STOSB"
Signature · 1 line
2.21.0