Difference between revisions of "Asm"

From Free Pascal wiki
Jump to navigationJump to search
 
(9 intermediate revisions by the same user not shown)
Line 1: Line 1:
 
{{Asm}}
 
{{Asm}}
  
The reserved word <code>asm</code> starts a [[Block|block]] of inline [[Assembly language|assembly]] code.
+
The [[Reserved word|reserved word]] <syntaxhighlight lang="pascal" inline>asm</syntaxhighlight> starts a [[Frame|frame]] of inline [[Assembly language|assembly]] code.
  
<syntaxhighlight>program asmDemo(input, output, stderr);
+
<syntaxhighlight lang="pascal" line highlight="3-6,17,22-26">program asmDemo(input, output, stderr);
  
 
// The $asmMode directive informs the compiler
 
// The $asmMode directive informs the compiler
Line 35: Line 35:
 
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|conditional compilation]]:
 
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|conditional compilation]]:
  
<syntaxhighlight>program sumExample(input, output, stderr);
+
<syntaxhighlight lang="pascal" line highlight="8,21,38">program sign(input, output, stderr);
  
{ iteratively calculates the sum over first n integers }
+
type
function iterativeSumFirstNIntegers(const n: longword): qword;
+
signumCodomain = -1..1;
{$ifdef CPUX86_64} // ============= optimized implementation
+
 
// assembler modifier appended to routine declaration
+
{ returns the sign of an integer }
 +
function signum({$ifNDef CPUx86_64} const {$endIf} x: longint): signumCodomain;
 +
{$ifDef CPUx86_64} // ============= optimized implementation
 
assembler;
 
assembler;
// you have to familiarize the compiler with symbols
 
// which are meant to be jump targets
 
{$goto on}
 
label
 
isfni_iterate;
 
 
{$asmMode intel}
 
{$asmMode intel}
 
asm
 
asm
// ecx is used as counter by loop instruction
+
xor rax, rax                  // ensure result is not wrong
mov ecx, n // ecx := n
+
                              // due to any residue
mov rax, 0 // rax := 0
+
isfni_iterate:
+
test x, x                    // x ≟ 0
add rax, qword(ecx) // rax := rax + ecx
+
setnz al                      // al ≔ ¬ZF
loop isfni_iterate // dec(ecx)
 
// if ecx <> 0 then goto isfni_iterate
 
 
 
// the @result macro represents the functions return value
+
sar x, 63                    // propagate sign-bit through reg.
mov @result, rax
+
cmovs rax, x                  // if SF then rax ≔ −1
// note, a list of modified registers (here ['rax', 'ecx'])
 
//      is ignored for pure assembler routines
 
 
end;
 
end;
 
{$else} // ========================== default implementation
 
{$else} // ========================== default implementation
var
 
i: longword;
 
x: qword;
 
 
begin
 
begin
x := 0; // mov rax, 0
+
// This is what math.sign virtually does.
for i := n downto 1 do // mov ecx, n
+
// The compiled code requires _two_ cmp instructions, though.
 +
if x > 0 then
 
begin
 
begin
x := x + i; // add rax, ecx
+
signum := 1;
end; // loop isfni_iterate
+
end
iterativeSumFirstNIntegers := x; // mov @result, rax
+
else if x < 0 then
 +
begin
 +
signum := -1;
 +
end
 +
else
 +
begin
 +
signum := 0;
 +
end;
 
end;
 
end;
{$endif}
+
{$endIf}
  
 
// M A I N =================================================
 
// M A I N =================================================
 
var
 
var
n: longword;
+
x: longint;
 
begin
 
begin
readLn(n);
+
readLn(x);
writeLn(iterativeSumFirstNIntegers(n));
+
writeLn(signum(x));
 
end.</syntaxhighlight>
 
end.</syntaxhighlight>
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 <syntaxhighlight lang="pascal" inline>assembler</syntaxhighlight> modifier and writing <syntaxhighlight lang="pascal" inline>asm</syntaxhighlight> instead of <syntaxhighlight lang="pascal" inline>begin</syntaxhighlight> 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”).
 
 
 
  
  
 
== see also ==
 
== see also ==
 
 
general
 
general
 
* [[The inline assembler parser]]
 
* [[The inline assembler parser]]
 
* [[Lazarus inline assembler]]
 
* [[Lazarus inline assembler]]
 +
* [[Label#assembler|<syntaxhighlight lang="pascal" inline>label</syntaxhighlight> § “assembler”]]
  
 
relevant compiler directives
 
relevant compiler directives
* [[sAsmmode|<code>$asmMode</code>]]
+
* [[$asmMode|<syntaxhighlight lang="pascal" inline>{$asmMode}</syntaxhighlight>]]
* [[sGoto|<code>$goto</code>]]
+
* [[$goto|<syntaxhighlight lang="pascal" inline>{$goto}</syntaxhighlight>]]
* [[sStackFrames|<code>$stackframes</code>]]
+
* [[$stackFrames|<syntaxhighlight lang="pascal" inline>{$stackframes}</syntaxhighlight>]]
  
 
special tasks
 
special tasks
Line 103: Line 99:
 
* [[AVR Programming|AVR programming]]
 
* [[AVR Programming|AVR programming]]
  
 +
[[Category:Code]]
 
[[Category:Reserved words]]
 
[[Category:Reserved words]]

Latest revision as of 15:55, 5 February 2021

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

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

 1program asmDemo(input, output, stderr);
 2
 3// The $asmMode directive informs the compiler
 4// which syntax is used in asm-blocks.
 5// Alternatives are 'att' (AT&T syntax) and 'direct'.
 6{$asmMode intel}
 7
 8var
 9	n, m: longint;
10begin
11	n := 42;
12	m := -7;
13	writeLn('n = ', n, '; m = ', m);
14	
15	// instead of declaring another temporary variable
16	// and writing "tmp := n; n := m; m := tmp;":
17	asm
18		mov eax, n  // eax := n
19		// xchg can only operate at most on one memory address
20		xchg eax, m // swaps values in eax and at m
21		mov n, eax  // n := eax (holding the former m value)
22	// an array of strings after the asm-block closing 'end'
23	// tells the compiler which registers have changed
24	// (you don't wanna mess with the compiler's notion
25	// which registers mean what)
26	end ['eax'];
27	
28	writeLn('n = ', n, '; m = ', m);
29end.

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:

 1program sign(input, output, stderr);
 2
 3type
 4	signumCodomain = -1..1;
 5
 6{ returns the sign of an integer }
 7function signum({$ifNDef CPUx86_64} const {$endIf} x: longint): signumCodomain;
 8{$ifDef CPUx86_64} // ============= optimized implementation
 9assembler;
10{$asmMode intel}
11asm
12	xor rax, rax                  // ensure result is not wrong
13	                              // due to any residue
14	
15	test x, x                     // x ≟ 0
16	setnz al                      // al ≔ ¬ZF
17	
18	sar x, 63                     // propagate sign-bit through reg.
19	cmovs rax, x                  // if SF then rax ≔ −1
20end;
21{$else} // ========================== default implementation
22begin
23	// This is what math.sign virtually does.
24	// The compiled code requires _two_ cmp instructions, though. 
25	if x > 0 then
26	begin
27		signum := 1;
28	end
29	else if x < 0 then
30	begin
31		signum := -1;
32	end
33	else
34	begin
35		signum := 0;
36	end;
37end;
38{$endIf}
39
40// M A I N =================================================
41var
42	x: longint;
43begin
44	readLn(x);
45	writeLn(signum(x));
46end.

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.


see also

general

relevant compiler directives

special tasks