Virtual value types during compile-time for static type safety, static optimizations and function overloading.

Tamas via Digitalmars-d-learn digitalmars-d-learn at puremagic.com
Sat Jul 18 03:06:05 PDT 2015


I made a thorough comparison using multiple compilers and a 
summary of the findings. In short, there is a runtime overhead.

I reduced the code to cut out the imports and made two versions 
with equivalent semantic content.
positive0.d contains the hand written specializations of the abs 
function.
positive.d contains the solution with function templates / static 
type analysis.

///////

/* positive0.d:

Compile & execute:
$ dmd positive0.d; ./positive0; echo $?
$ ldc2 positive0.d; ./positive0; echo $?

generate ASM source:
$ dmd positive0.d; gobjdump -d positive0.o > positive0.dmd.s
$ ldc2 positive0.d -output-s

*/

int absPositive(int n) {
   return n;
}

int abs(int n) {
   return (n>=0) ? n : -n;
}

int square(int x) {
   return x * x;
}

int main() {
   return !((abs(-16) == 16)
     && (abs(3) == 3)
     && (square(5).abs == 25)
     && (square(-4).abs == 16));
}

///////

/* positive.d:

Compile & execute:
$ dmd positive.d; ./positive; echo $?
$ ldc2 positive.d; ./positive; echo $?

generate ASM source:
$ dmd positive.d; gobjdump -d positive.o > positive.dmd.s
$ ldc2 positive.d -output-s

*/
struct Positive {
   int num;
   alias num this;
}

Positive abs(T)(T n) {
   static if (is(T == Positive)) {
     return n;
   } else {
     return Positive((n >= 0) ? n : -n);
   }
}

Positive square(int x) {
   return Positive(x * x);
}

int main() {
   return !((abs(-16) == 16)
     && (abs(3) == 3)
     && (square(5).abs == 25)
     && (square(-4).abs == 16));
}

///////

I compared the generated asms. The asm code was substantially 
longer in case of non-hand written specializations of the abs 
function.

The 'optimized' versions of the abs function were equivalent, but 
the 'non-optimzed' versions shows the runtime overhead for dmd 
and ldc2 as well, a double 'mov' commands instead of a single 
ones;

The compiled hand written code was roughly half the size for both 
compilers:

File sizes:
ldc:
2678 positive0.s
4313 positive.s

dmd:
3442 positive0.dmd.s
8701 positive.dmd.s

You can see the abs functions below, and you can spot the double 
'mov' operations:

positive.dmd.s:
0000000000000230 
<_D8positive10__T3absTiZ3absFNaNbNiNfiZS8positive8Positive>:
  230:	55                   	push   %rbp
  231:	48 8b ec             	mov    %rsp,%rbp
  234:	48 83 ec 10          	sub    $0x10,%rsp
  238:	85 ff                	test   %edi,%edi
  23a:	78 02                	js     23e 
<_D8positive10__T3absTiZ3absFNaNbNiNfiZS8positive8Positive+0xe>
  23c:	eb 02                	jmp    240 
<_D8positive10__T3absTiZ3absFNaNbNiNfiZS8positive8Positive+0x10>
  23e:	f7 df                	neg    %edi
  240:	89 7d f0             	mov    %edi,-0x10(%rbp)
  243:	48 89 f8             	mov    %rdi,%rax
  246:	c9                   	leaveq
  247:	c3                   	retq

0000000000000248 
<_D8positive28__T3absTS8positive8PositiveZ3absFNaNbNiNfS8positive8PositiveZS8positive8Positive>:
  248:	55                   	push   %rbp
  249:	48 8b ec             	mov    %rsp,%rbp
  24c:	48 83 ec 10          	sub    $0x10,%rsp
  250:	48 89 f8             	mov    %rdi,%rax
  253:	c9                   	leaveq
  254:	c3                   	retq
  255:	0f 1f 00             	nopl   (%rax)



positive0.dmd.s:
00000000000000a0 <_D9positive011absPositiveFiZi>:
   a0:	55                   	push   %rbp
   a1:	48 8b ec             	mov    %rsp,%rbp
   a4:	48 83 ec 10          	sub    $0x10,%rsp
   a8:	48 89 f8             	mov    %rdi,%rax
   ab:	c9                   	leaveq
   ac:	c3                   	retq
   ad:	0f 1f 00             	nopl   (%rax)

00000000000000b0 <_D9positive03absFiZi>:
   b0:	55                   	push   %rbp
   b1:	48 8b ec             	mov    %rsp,%rbp
   b4:	48 83 ec 10          	sub    $0x10,%rsp
   b8:	85 ff                	test   %edi,%edi
   ba:	78 05                	js     c1 <_D9positive03absFiZi+0x11>
   bc:	48 89 f8             	mov    %rdi,%rax
   bf:	eb 05                	jmp    c6 <_D9positive03absFiZi+0x16>
   c1:	48 89 f8             	mov    %rdi,%rax
   c4:	f7 d8                	neg    %eax
   c6:	c9                   	leaveq
   c7:	c3                   	retq


ldc2:
positive.s:

__D8positive10__T3absTiZ3absFNaNbNiNfiZS8positive8Positive:
	.cfi_startproc
	movl	%edi, -4(%rsp)
	cmpl	$0, -4(%rsp)
	jl	LBB2_2
	leaq	-4(%rsp), %rax
	movq	%rax, -16(%rsp)
	jmp	LBB2_3
LBB2_2:
	leaq	-20(%rsp), %rax
	xorl	%ecx, %ecx
	subl	-4(%rsp), %ecx
	movl	%ecx, -20(%rsp)
	movq	%rax, -16(%rsp)
LBB2_3:
	movq	-16(%rsp), %rax
	movl	(%rax), %ecx
	movl	%ecx, -8(%rsp)
	movl	%ecx, %eax
	retq
	.cfi_endproc

	.globl	__D8positive28__T3absTS8positive8PositiveZ3absFNaNbNiNfS8positive8PositiveZS8positive8Positive
	.weak_definition	__D8positive28__T3absTS8positive8PositiveZ3absFNaNbNiNfS8positive8PositiveZS8positive8Positive
	.align	4, 0x90
__D8positive28__T3absTS8positive8PositiveZ3absFNaNbNiNfS8positive8PositiveZS8positive8Positive:
	.cfi_startproc
	movl	%edi, -8(%rsp)
	movl	%edi, %eax
	retq
	.cfi_endproc

	.section	__TEXT,__text,regular,pure_instructions
	.align	4, 0x90


positive0.s:
__D9positive011absPositiveFiZi:
	.cfi_startproc
	movl	%edi, -4(%rsp)
	movl	-4(%rsp), %eax
	retq
	.cfi_endproc

	.globl	__D9positive03absFiZi
	.align	4, 0x90
__D9positive03absFiZi:
	.cfi_startproc
	movl	%edi, -4(%rsp)
	cmpl	$0, -4(%rsp)
	jl	LBB1_2
	leaq	-4(%rsp), %rax
	movq	%rax, -16(%rsp)
	jmp	LBB1_3
LBB1_2:
	leaq	-20(%rsp), %rax
	xorl	%ecx, %ecx
	subl	-4(%rsp), %ecx
	movl	%ecx, -20(%rsp)
	movq	%rax, -16(%rsp)
LBB1_3:
	movq	-16(%rsp), %rax
	movl	(%rax), %eax
	retq
	.cfi_endproc

	.globl	__D9positive06squareFiZi
	.align	4, 0x90


my compilers:

$ ldc2 -version
LDC - the LLVM D compiler (6d3923):
   based on DMD v2.066.1 and LLVM 3.6.1
   Default target: x86_64-apple-darwin14.4.0
   Host CPU: core-avx2

$ dmd --version
DMD64 D Compiler v2.067




More information about the Digitalmars-d-learn mailing list