Difference between revisions of "Asm"

From Free Pascal wiki
Jump to navigationJump to search
m (tc)
(same type)
Line 64: Line 64:
 
{$else} // ========================== default implementation
 
{$else} // ========================== default implementation
 
var
 
var
i: word;
+
i: longword;
 
x: qword;
 
x: qword;
 
begin
 
begin
Line 85: Line 85:
 
As you can see, you can implement whole routines in assembly language, by adding the <code>assembler</code> modifier and writing <code>asm</code> instead of <code>begin</code> for the implementation block.
 
As you can see, you can implement whole routines in assembly language, by adding the <code>assembler</code> modifier and writing <code>asm</code> instead of <code>begin</code> for the implementation block.
 
Of course in a production program, you would use an algorithm applying the formula <code>sum := (n * (n + 1)) div 2</code> (“Gaussian sum formula”).
 
Of course in a production program, you would use an algorithm applying the formula <code>sum := (n * (n + 1)) div 2</code> (“Gaussian sum formula”).
 +
  
  

Revision as of 18:07, 1 February 2018

Deutsch (de) English (en) español (es) suomi (fi)

The reserved word asm starts a block of inline assembly code.

program asmDemo(input, output, stderr);

// The $asmMode directive informs the compiler
// which syntax is used in asm-blocks.
// Alternatives are 'att' (AT&T syntax) and 'direct'.
{$asmMode intel}

var
	n, m: longint;
begin
	n := 42;
	m := -7;
	writeLn('n = ', n, '; m = ', m);
	
	// instead of declaring another temporary variable
	// and writing "tmp := n; n := m; m := tmp;":
	asm
		mov eax, n  // eax := n
		// xchg can only operate at most on one memory address
		xchg eax, m // swaps values in eax and at m
		mov n, eax  // n := eax (holding the former m value)
	// an array of strings after the asm-block closing 'end'
	// tells the compiler which registers have changed
	// (you don't wanna mess with the compiler's notion
	// which registers mean what)
	end ['eax'];
	
	writeLn('n = ', n, '; m = ', m);
end.

In order to maintain portability between platforms (i.e. your code still compiles for many targets), while optimizing for specific targets, you want to set up conditional compilation:

program sumExample(input, output, stderr);

{ iteratively calculates the sum over first n integers }
function iterativeSumFirstNIntegers(const n: longword): qword;
{$ifdef CPUX86_64} // ============= optimized implementation
// assembler modifier appended to routine declaration
assembler;
// you have to familiarize the compiler with symbols
// which are meant to be jump targets
{$goto on}
label
	isfni_iterate;
{$asmMode intel}
asm
	// ecx is used as counter by loop instruction
	mov ecx, n // ecx := n
	mov rax, 0 // rax := 0
isfni_iterate:
	add rax, qword(ecx) // rax := rax + ecx
	loop isfni_iterate // dec(ecx)
	// if ecx <> 0 then goto isfni_iterate
	
	// the @result macro represents the functions return value
	mov @result, rax
// note, a list of modified registers (here ['rax', 'ecx'])
//       is ignored for pure assembler routines
end;
{$else} // ========================== default implementation
var
	i: longword;
	x: qword;
begin
	x := 0; // mov rax, 0
	for i := n downto 1 do // mov ecx, n
	begin
		x := x + i; // add rax, ecx
	end; // loop isfni_iterate
	iterativeSumFirstNIntegers := x; // mov @result, rax
end;
{$endif}

// M A I N =================================================
var
	n: longword;
begin
	readLn(n);
	writeLn(iterativeSumFirstNIntegers(n));
end.

As you can see, you can implement whole routines in assembly language, by adding the assembler modifier and writing asm instead of begin for the implementation block. Of course in a production program, you would use an algorithm applying the formula sum := (n * (n + 1)) div 2 (“Gaussian sum formula”).


see also

general

relevant compiler directives

special tasks