Difference between revisions of "Asm"
From Free Pascal wiki
Jump to navigationJump to searchm (c) |
(changed example with Label and optimized it) |
||
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 | + | <syntaxhighlight>program sign(input, output, stderr); |
− | { | + | type |
− | function | + | signumCodomain = -1..1; |
− | {$ifdef | + | |
− | + | { returns the sign of an integer } | |
+ | function signum(const x: longint): signumCodomain; | ||
+ | {$ifdef CPUx86_64} // ============= optimized implementation | ||
assembler; | assembler; | ||
− | |||
− | |||
− | |||
− | |||
− | |||
{$asmMode intel} | {$asmMode intel} | ||
asm | asm | ||
− | // | + | // load constants: cmov cannot handle immediates |
− | + | // xor-instruction modifies flags => put it prior test | |
− | + | xor r8, r8 // r8 := 0 | |
− | + | ||
− | + | // comparison pulled up front for pipelining | |
− | + | test x, x // x = 0 ? | |
− | // | + | |
+ | // load constants, since cmov cannot handle immediates | ||
+ | mov r9, -1 // r9 := -1 | ||
− | // | + | // determine result |
− | mov | + | mov eax, 1 // result := 1 |
− | // | + | cmovl eax, r9 // if x < 0 then result := -1 |
− | // | + | cmove eax, r8 // if x = 0 then result := 0 |
end; | end; | ||
{$else} // ========================== default implementation | {$else} // ========================== default implementation | ||
− | |||
− | |||
− | |||
begin | begin | ||
− | + | // This is what virtually math.sign does. | |
− | + | // The compiled code requires _two_ cmp instructions, though. | |
+ | if x > 0 then | ||
begin | begin | ||
− | x := | + | signum := 1; |
− | end | + | end |
− | + | else if x < 0 then | |
+ | begin | ||
+ | signum := -1; | ||
+ | end | ||
+ | else | ||
+ | begin | ||
+ | signum := 0; | ||
+ | end; | ||
end; | end; | ||
{$endif} | {$endif} | ||
Line 78: | Line 82: | ||
// M A I N ================================================= | // M A I N ================================================= | ||
var | var | ||
− | + | x: longint; | |
begin | begin | ||
− | readLn( | + | readLn(x); |
− | writeLn( | + | 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 <code>assembler</code> modifier and writing <code>asm</code> instead of <code>begin</code> for the implementation block. | ||
− | |||
− | |||
Line 93: | Line 95: | ||
* [[The inline assembler parser]] | * [[The inline assembler parser]] | ||
* [[Lazarus inline assembler]] | * [[Lazarus inline assembler]] | ||
+ | * [[Label|<code>label</code>]] | ||
relevant compiler directives | relevant compiler directives |
Revision as of 17:05, 8 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 sign(input, output, stderr);
type
signumCodomain = -1..1;
{ returns the sign of an integer }
function signum(const x: longint): signumCodomain;
{$ifdef CPUx86_64} // ============= optimized implementation
assembler;
{$asmMode intel}
asm
// load constants: cmov cannot handle immediates
// xor-instruction modifies flags => put it prior test
xor r8, r8 // r8 := 0
// comparison pulled up front for pipelining
test x, x // x = 0 ?
// load constants, since cmov cannot handle immediates
mov r9, -1 // r9 := -1
// determine result
mov eax, 1 // result := 1
cmovl eax, r9 // if x < 0 then result := -1
cmove eax, r8 // if x = 0 then result := 0
end;
{$else} // ========================== default implementation
begin
// This is what virtually math.sign does.
// The compiled code requires _two_ cmp instructions, though.
if x > 0 then
begin
signum := 1;
end
else if x < 0 then
begin
signum := -1;
end
else
begin
signum := 0;
end;
end;
{$endif}
// M A I N =================================================
var
x: longint;
begin
readLn(x);
writeLn(signum(x));
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.
see also
general
relevant compiler directives
special tasks