Чем отличаются эти две функции?

Низкоуровневое программирование портов, микроконтроллеров и т.д.

Модератор: Andy

Ответить
Absurd
Сообщения: 1213
Зарегистрирован: 26 фев 2004, 13:24
Откуда: Pietari, Venäjä
Контактная информация:

23 дек 2015, 17:45

Одну LLVM скомпилировал при наличии реальных данных от профилировщика, другую - без.
Они не идентичные, но разница что-то не ощущается совершенно.
2B OR NOT(2B) = FF
Absurd
Сообщения: 1213
Зарегистрирован: 26 фев 2004, 13:24
Откуда: Pietari, Venäjä
Контактная информация:

23 дек 2015, 17:45

С профилировщиком

Код: Выделить всё

	.text
	.def	 jit_fn3;
	.scl	2;
	.type	32;
	.endef
	.globl	jit_fn3
	.align	16, 0x90
jit_fn3:                                # @jit_fn3
.Ltmp0:
.seh_proc jit_fn3
# BB#0:                                 # %Block_200.split
	pushq	%r15
.Ltmp1:
	.seh_pushreg 15
	pushq	%r14
.Ltmp2:
	.seh_pushreg 14
	pushq	%r13
.Ltmp3:
	.seh_pushreg 13
	pushq	%r12
.Ltmp4:
	.seh_pushreg 12
	pushq	%rsi
.Ltmp5:
	.seh_pushreg 6
	pushq	%rdi
.Ltmp6:
	.seh_pushreg 7
	pushq	%rbp
.Ltmp7:
	.seh_pushreg 5
	pushq	%rbx
.Ltmp8:
	.seh_pushreg 3
	subq	$40, %rsp
.Ltmp9:
	.seh_stackalloc 40
.Ltmp10:
	.seh_endprologue
	movq	%rcx, %r15
	xorl	%edx, %edx
	callq	_readRegUint
	movq	%rax, %rbx
	movl	$4, %edx
	movq	%r15, %rcx
	callq	_readRegUint
	movl	$3, %edx
	movq	%r15, %rcx
	callq	_readRegUint
	movl	$7, %edx
	movq	%r15, %rcx
	callq	_readRegUint
	movl	$2, %edx
	movq	%r15, %rcx
	callq	_readRegUint
	movl	$1, %edx
	movq	%r15, %rcx
	callq	_readRegUint
	movq	%rax, %r14
	movl	$5, %edx
	movq	%r15, %rcx
	callq	_readRegUint
	movl	$6, %edx
	movq	%r15, %rcx
	callq	_readRegUint
	cmpq	$99999999, %rbx         # imm = 0x5F5E0FF
	seta	%al
	movzbl	%al, %eax
	sbbq	$0, %rax
	testq	%rax, %rax
	jle	.LBB0_1
# BB#14:                                # %Block_21c
	movl	$100000000, %r8d        # imm = 0x5F5E100
	movq	%r15, %rcx
	movq	%rbx, %rdx
	callq	_udiv128
	movq	%rax, %rdx
	cmpq	$9999, %rdx             # imm = 0x270F
	seta	%al
	movzbl	%al, %eax
	sbbq	$0, %rax
	movl	$9, %edi
	testq	%rax, %rax
	jg	.LBB0_2
	jmp	.LBB0_3
.LBB0_1:                                # %Block_214
	cmpq	$9999, %rbx             # imm = 0x270F
	seta	%al
	movzbl	%al, %eax
	sbbq	$0, %rax
	movl	$1, %edi
	testq	%rax, %rax
	movq	%rbx, %rdx
	jle	.LBB0_3
.LBB0_2:                                # %Block_228
	movl	$10000, %r8d            # imm = 0x2710
	movq	%r15, %rcx
	callq	_udiv128
	movq	%rax, %rdx
	addq	$4, %rdi
.LBB0_3:                                # %Block_234
	cmpq	$99, %rdx
	seta	%al
	movzbl	%al, %eax
	sbbq	$0, %rax
	testq	%rax, %rax
	jle	.LBB0_5
# BB#4:                                 # %Block_23c
	movl	$100, %r8d
	movq	%r15, %rcx
	callq	_udiv128
	addq	$2, %rdi
	cmpq	$9, %rax
.LBB0_6:                                # %Block_244
	seta	%al
	movzbl	%al, %eax
	sbbq	$0, %rax
	testq	%rax, %rax
	jle	.LBB0_9
# BB#7:                                 # %Block_24c
	leaq	1(%rdi), %rsi
	movl	%esi, %edx
	xorl	%r9d, %r9d
	movq	%r15, %rcx
	movq	%r14, %r8
	callq	_storeMemUint8
	testq	%rdi, %rdi
	js	.LBB0_13
# BB#8:
	movq	%rdi, %rbp
	movq	%rdi, %r13
.LBB0_10:                               # %Block_270
	leaq	(%r14,%rbp), %rdi
	subl	%r13d, %esi
	addl	$-2, %esi
	movslq	%esi, %r12
	movl	$10, %r8d
	movq	%r15, %rcx
	movq	%rbx, %rdx
	callq	_udiv128
	movq	%rax, %rbx
	movl	$6, %edx
	movq	%r15, %rcx
	callq	_readSpRegUint
	leal	48(%rax), %r9d
	xorl	%r8d, %r8d
	movq	%r15, %rcx
	movq	%rdi, %rdx
	callq	_storeMemUint8
	leaq	-1(%r13), %rsi
	movslq	%esi, %rax
	cmpq	%r12, %rax
	setg	%cl
	movzbl	%cl, %ecx
	cmpq	%rax, %r12
	setg	%al
	movzbl	%al, %eax
	cmpq	%rax, %rcx
	je	.LBB0_13
# BB#11:                                # %Block_288.preheader
	leaq	-1(%r14,%rbp), %rdi
	shlq	$32, %r13
	movabsq	$-8589934592, %rbp      # imm = 0xFFFFFFFE00000000
	addq	%r13, %rbp
	movabsq	$-4294967296, %r14      # imm = 0xFFFFFFFF00000000
	.align	16, 0x90
.LBB0_12:                               # %Block_288
                                        # =>This Inner Loop Header: Depth=1
	movl	$10, %r8d
	movq	%r15, %rcx
	movq	%rbx, %rdx
	callq	_udiv128
	movq	%rax, %rbx
	movl	$6, %edx
	movq	%r15, %rcx
	callq	_readSpRegUint
	leal	48(%rax), %r9d
	xorl	%r8d, %r8d
	movq	%r15, %rcx
	movq	%rdi, %rdx
	callq	_storeMemUint8
	decq	%rdi
	movq	%rbp, %rax
	sarq	$32, %rax
	cmpq	%r12, %rax
	setg	%cl
	movzbl	%cl, %ecx
	cmpq	%rax, %r12
	setg	%al
	movzbl	%al, %eax
	addq	%r14, %rbp
	decq	%rsi
	cmpq	%rax, %rcx
	jne	.LBB0_12
.LBB0_13:                               # %Block_2b8
	xorl	%edx, %edx
	movq	%r15, %rcx
	callq	_pop
	nop
	addq	$40, %rsp
	popq	%rbx
	popq	%rbp
	popq	%rdi
	popq	%rsi
	popq	%r12
	popq	%r13
	popq	%r14
	popq	%r15
	retq
.LBB0_9:                                # %Block_250
	movl	%edi, %edx
	xorl	%r9d, %r9d
	movq	%r15, %rcx
	movq	%r14, %r8
	callq	_storeMemUint8
	leaq	-1(%rdi), %r13
	movslq	%r13d, %rbp
	testq	%rbp, %rbp
	movq	%rdi, %rsi
	jns	.LBB0_10
	jmp	.LBB0_13
.LBB0_5:                                # %Block_244
	cmpq	$9, %rdx
	jmp	.LBB0_6
	.seh_handlerdata
	.text
.Ltmp11:
	.seh_endproc
2B OR NOT(2B) = FF
Absurd
Сообщения: 1213
Зарегистрирован: 26 фев 2004, 13:24
Откуда: Pietari, Venäjä
Контактная информация:

23 дек 2015, 17:46

Без данных профиля

Код: Выделить всё

	.text
	.def	 jit_fn3;
	.scl	2;
	.type	32;
	.endef
	.globl	jit_fn3
	.align	16, 0x90
jit_fn3:                                # @jit_fn3
.Ltmp0:
.seh_proc jit_fn3
# BB#0:                                 # %Block_200.split
	pushq	%r15
.Ltmp1:
	.seh_pushreg 15
	pushq	%r14
.Ltmp2:
	.seh_pushreg 14
	pushq	%r13
.Ltmp3:
	.seh_pushreg 13
	pushq	%r12
.Ltmp4:
	.seh_pushreg 12
	pushq	%rsi
.Ltmp5:
	.seh_pushreg 6
	pushq	%rdi
.Ltmp6:
	.seh_pushreg 7
	pushq	%rbp
.Ltmp7:
	.seh_pushreg 5
	pushq	%rbx
.Ltmp8:
	.seh_pushreg 3
	subq	$40, %rsp
.Ltmp9:
	.seh_stackalloc 40
.Ltmp10:
	.seh_endprologue
	movq	%rcx, %r15
	xorl	%edx, %edx
	callq	_readRegUint
	movq	%rax, %rbx
	movl	$4, %edx
	movq	%r15, %rcx
	callq	_readRegUint
	movl	$3, %edx
	movq	%r15, %rcx
	callq	_readRegUint
	movl	$7, %edx
	movq	%r15, %rcx
	callq	_readRegUint
	movl	$2, %edx
	movq	%r15, %rcx
	callq	_readRegUint
	movl	$1, %edx
	movq	%r15, %rcx
	callq	_readRegUint
	movq	%rax, %r14
	movl	$5, %edx
	movq	%r15, %rcx
	callq	_readRegUint
	movl	$6, %edx
	movq	%r15, %rcx
	callq	_readRegUint
	cmpq	$99999999, %rbx         # imm = 0x5F5E0FF
	seta	%al
	movzbl	%al, %eax
	sbbq	$0, %rax
	testq	%rax, %rax
	jle	.LBB0_1
# BB#13:                                # %Block_21c
	movl	$100000000, %r8d        # imm = 0x5F5E100
	movq	%r15, %rcx
	movq	%rbx, %rdx
	callq	_udiv128
	cmpq	$9999, %rax             # imm = 0x270F
	seta	%cl
	movzbl	%cl, %ecx
	sbbq	$0, %rcx
	movl	$9, %edi
	testq	%rcx, %rcx
	jg	.LBB0_2
	jmp	.LBB0_3
.LBB0_1:                                # %Block_214
	cmpq	$9999, %rbx             # imm = 0x270F
	seta	%al
	movzbl	%al, %eax
	sbbq	$0, %rax
	movl	$1, %edi
	testq	%rax, %rax
	movq	%rbx, %rax
	jle	.LBB0_3
.LBB0_2:                                # %Block_228
	movl	$10000, %r8d            # imm = 0x2710
	movq	%r15, %rcx
	movq	%rax, %rdx
	callq	_udiv128
	addq	$4, %rdi
.LBB0_3:                                # %Block_234
	cmpq	$99, %rax
	seta	%cl
	movzbl	%cl, %ecx
	sbbq	$0, %rcx
	testq	%rcx, %rcx
	jle	.LBB0_5
# BB#4:                                 # %Block_23c
	movl	$100, %r8d
	movq	%r15, %rcx
	movq	%rax, %rdx
	callq	_udiv128
	addq	$2, %rdi
.LBB0_5:                                # %Block_244
	cmpq	$9, %rax
	seta	%al
	movzbl	%al, %eax
	sbbq	$0, %rax
	testq	%rax, %rax
	jg	.LBB0_6
# BB#8:                                 # %Block_250
	movl	%edi, %edx
	xorl	%r9d, %r9d
	movq	%r15, %rcx
	movq	%r14, %r8
	callq	_storeMemUint8
	leaq	-1(%rdi), %r13
	movslq	%r13d, %rbp
	testq	%rbp, %rbp
	movq	%rdi, %rsi
	jns	.LBB0_9
	jmp	.LBB0_12
.LBB0_6:                                # %Block_24c
	leaq	1(%rdi), %rsi
	movl	%esi, %edx
	xorl	%r9d, %r9d
	movq	%r15, %rcx
	movq	%r14, %r8
	callq	_storeMemUint8
	testq	%rdi, %rdi
	js	.LBB0_12
# BB#7:
	movq	%rdi, %rbp
	movq	%rdi, %r13
.LBB0_9:                                # %Block_270
	leaq	(%r14,%rbp), %rdi
	subl	%r13d, %esi
	addl	$-2, %esi
	movslq	%esi, %r12
	movl	$10, %r8d
	movq	%r15, %rcx
	movq	%rbx, %rdx
	callq	_udiv128
	movq	%rax, %rbx
	movl	$6, %edx
	movq	%r15, %rcx
	callq	_readSpRegUint
	leal	48(%rax), %r9d
	xorl	%r8d, %r8d
	movq	%r15, %rcx
	movq	%rdi, %rdx
	callq	_storeMemUint8
	leaq	-1(%r13), %rsi
	movslq	%esi, %rax
	cmpq	%r12, %rax
	setg	%cl
	movzbl	%cl, %ecx
	cmpq	%rax, %r12
	setg	%al
	movzbl	%al, %eax
	cmpq	%rax, %rcx
	je	.LBB0_12
# BB#10:                                # %Block_288.preheader
	leaq	-1(%r14,%rbp), %rdi
	shlq	$32, %r13
	movabsq	$-8589934592, %rbp      # imm = 0xFFFFFFFE00000000
	addq	%r13, %rbp
	movabsq	$-4294967296, %r14      # imm = 0xFFFFFFFF00000000
	.align	16, 0x90
.LBB0_11:                               # %Block_288
                                        # =>This Inner Loop Header: Depth=1
	movl	$10, %r8d
	movq	%r15, %rcx
	movq	%rbx, %rdx
	callq	_udiv128
	movq	%rax, %rbx
	movl	$6, %edx
	movq	%r15, %rcx
	callq	_readSpRegUint
	leal	48(%rax), %r9d
	xorl	%r8d, %r8d
	movq	%r15, %rcx
	movq	%rdi, %rdx
	callq	_storeMemUint8
	decq	%rdi
	movq	%rbp, %rax
	sarq	$32, %rax
	cmpq	%r12, %rax
	setg	%cl
	movzbl	%cl, %ecx
	cmpq	%rax, %r12
	setg	%al
	movzbl	%al, %eax
	addq	%r14, %rbp
	decq	%rsi
	cmpq	%rax, %rcx
	jne	.LBB0_11
.LBB0_12:                               # %Block_2b8
	xorl	%edx, %edx
	movq	%r15, %rcx
	callq	_pop
	nop
	addq	$40, %rsp
	popq	%rbx
	popq	%rbp
	popq	%rdi
	popq	%rsi
	popq	%r12
	popq	%r13
	popq	%r14
	popq	%r15
	retq
	.seh_handlerdata
	.text
.Ltmp11:
	.seh_endproc

2B OR NOT(2B) = FF
Absurd
Сообщения: 1213
Зарегистрирован: 26 фев 2004, 13:24
Откуда: Pietari, Venäjä
Контактная информация:

23 дек 2015, 18:00

Данные профилировщика выгдядят как-то так. Как видно, самый тугой цикл здесь #288-#2b4

Изображение
2B OR NOT(2B) = FF
Аватара пользователя
somewhere
Сообщения: 1837
Зарегистрирован: 31 авг 2006, 17:14
Откуда: 71 RUS
Контактная информация:

23 дек 2015, 20:39

Синтаксис непривычный, сложный =)
Код практически идентичный, только разная интерпретация результата, возвращаемого процедурой _udiv128. В одном случае он в RAX, а в другом в RDX. Соответственно и перестраиваются инструкции, которые от них зависят (или влияют)
Без профилировщика понятно, что основные потери идут на CALL (_storeMemUint8, _udiv128, etc.) - это как я понял, обертка для безопасного деления, записи в память и т.д.
Основная цель - оптимизация?
It's a long way to the top if you wanna rock'n'roll
Absurd
Сообщения: 1213
Зарегистрирован: 26 фев 2004, 13:24
Откуда: Pietari, Venäjä
Контактная информация:

23 дек 2015, 20:56

Меня сейчас интересует на что повлияли данные профилировщика, почему LLVM переставил инструкции именно таким образом когда достоверно узнал склько раз реально срабатывает каждый бранч. Две недели отлаживал профилировщик чтобы он вносил минимум дополнительного оверхеда и при этом экспортировал удобный весовой граф для последующей jit-компиляции, а выхлоп получился нулевой.

От _storeMem не избавиться похоже никак так как там эмуляция виртуальной памяти другой архитектуры, _udiv128 надо заменить на нативную инструкцию которая в x86_64 есть. Но в первую очередь - выкинуть эти идиотские _readRegUint, результат которых отбрасывается и не используется. Начну этим заниматься уже завтра.

_readSpReg, кстати, это чтение остатка от деления который на эмулируемой архитектуре идет в спецрегистр. Ее надо слить с _udiv128 таким образом чтобы перед выходом из процедуры срабатывал некий триггер и последний остаток всеже записывался в спецрегистр для прозрачной эмуляции, это будет отдельный большой кариес.

Возможен также вариант что оптимизированный вариант у меня не запускался никогда, так как по дефолту встраиваемый LLVM JIT компилирует код проще чем это делает полный стационарный LLVM компилятор чей асмовый аутпут я запостил, это тоже надо проверить.
2B OR NOT(2B) = FF
Ответить