A proposal for inline assembly


(Ethin Probst) #1

Hello all,
My name is Ethin and I am new to this community. However, I certainly
am no newbie when it comes to software development, and have emailed
all of you to file a proposal of inline assembly in Swift. The
assembly language would be within an asm {...} block. The asm keyword
could also take an optional argument: the type of assembler to use. As
there are many different types of assemblers out there, I thought this
should be implemented as well. Furthermore, the asm keyword could also
take a second optional argument: the extra arguments to pass to the
assembler. The full syntax of the keyword would look something like:
asm (assembler, assembler_args)
{
    // asm goes here...
}
For instance, below is a hello world application in NASM assembly
language (taken from Wikipedia) with no extra arguments for Linux:
asm ("nasm")
{
global _start

section .text
_start:
  mov eax, 4 ; write
  mov ebx, 1 ; stdout
  mov ecx, msg
  mov edx, msg.len
  int 0x80 ; write(stdout, msg, strlen(msg));

  mov eax, 1 ; exit
  mov ebx, 0
  int 0x80 ; exit(0)

section .data
msg: db "Hello, world!", 10
.len: equ $ - msg
}
And here is one for Mac OS X with the -G, -Fstabs, and -felf arguments to nasm:
asm ("nasm", "-G -Fstabs -felf")
{
global _start

section .data

  query_string: db "Enter a character: "
  query_string_len: equ $ - query_string
  out_string: db "You have input: "
  out_string_len: equ $ - out_string

section .bss

  in_char: resw 4

section .text

_start:

  mov rax, 0x2000004 ; put the write-system-call-code into register rax
  mov rdi, 1 ; tell kernel to use stdout
  mov rsi, query_string ; rsi is where the kernel expects to find the
address of the message
  mov rdx, query_string_len ; and rdx is where the kernel expects to
find the length of the message
  syscall

  ; read in the character
  mov rax, 0x2000003 ; read system call
  mov rdi, 0 ; stdin
  mov rsi, in_char ; address for storage, declared in section .bss
  mov rdx, 2 ; get 2 bytes from the kernel's buffer (one for the
carriage return)
  syscall

  ; show user the output
  mov rax, 0x2000004 ; write system call
  mov rdi, 1 ; stdout
  mov rsi, out_string
  mov rdx, out_string_len
  syscall

  mov rax, 0x2000004 ; write system call
  mov rdi, 1 ; stdout
  mov rsi, in_char
  mov rdx, 2 ; the second byte is to apply the carriage return
expected in the string
  syscall

  ; exit system call
  mov rax, 0x2000001 ; exit system call
        xor rdi, rdi
  syscall
}
Again, both assembly language examples were taken from Wikipedia. I am
no asm expert, I assure you, and with the lack of material available
on assembly language these days... it's quite hard to learn it. I
thank you for taking your time to read this proposal and have a nice
day!

···

--
Signed,
Ethin D. Probst


(Félix Cloutier) #2

Do you have a use case for writing a whole assembly program in a .swift file rather than in an assembly file?

···

Le 3 déc. 2016 à 15:12, Ethin Probst via swift-evolution <swift-evolution@swift.org> a écrit :

Hello all,
My name is Ethin and I am new to this community. However, I certainly
am no newbie when it comes to software development, and have emailed
all of you to file a proposal of inline assembly in Swift. The
assembly language would be within an asm {...} block. The asm keyword
could also take an optional argument: the type of assembler to use. As
there are many different types of assemblers out there, I thought this
should be implemented as well. Furthermore, the asm keyword could also
take a second optional argument: the extra arguments to pass to the
assembler. The full syntax of the keyword would look something like:
asm (assembler, assembler_args)
{
   // asm goes here...
}
For instance, below is a hello world application in NASM assembly
language (taken from Wikipedia) with no extra arguments for Linux:
asm ("nasm")
{
global _start

section .text
_start:
  mov eax, 4 ; write
  mov ebx, 1 ; stdout
  mov ecx, msg
  mov edx, msg.len
  int 0x80 ; write(stdout, msg, strlen(msg));

  mov eax, 1 ; exit
  mov ebx, 0
  int 0x80 ; exit(0)

section .data
msg: db "Hello, world!", 10
.len: equ $ - msg
}
And here is one for Mac OS X with the -G, -Fstabs, and -felf arguments to nasm:
asm ("nasm", "-G -Fstabs -felf")
{
global _start

section .data

  query_string: db "Enter a character: "
  query_string_len: equ $ - query_string
  out_string: db "You have input: "
  out_string_len: equ $ - out_string

section .bss

  in_char: resw 4

section .text

_start:

  mov rax, 0x2000004 ; put the write-system-call-code into register rax
  mov rdi, 1 ; tell kernel to use stdout
  mov rsi, query_string ; rsi is where the kernel expects to find the
address of the message
  mov rdx, query_string_len ; and rdx is where the kernel expects to
find the length of the message
  syscall

  ; read in the character
  mov rax, 0x2000003 ; read system call
  mov rdi, 0 ; stdin
  mov rsi, in_char ; address for storage, declared in section .bss
  mov rdx, 2 ; get 2 bytes from the kernel's buffer (one for the
carriage return)
  syscall

  ; show user the output
  mov rax, 0x2000004 ; write system call
  mov rdi, 1 ; stdout
  mov rsi, out_string
  mov rdx, out_string_len
  syscall

  mov rax, 0x2000004 ; write system call
  mov rdi, 1 ; stdout
  mov rsi, in_char
  mov rdx, 2 ; the second byte is to apply the carriage return
expected in the string
  syscall

  ; exit system call
  mov rax, 0x2000001 ; exit system call
       xor rdi, rdi
  syscall
}
Again, both assembly language examples were taken from Wikipedia. I am
no asm expert, I assure you, and with the lack of material available
on assembly language these days... it's quite hard to learn it. I
thank you for taking your time to read this proposal and have a nice
day!
--
Signed,
Ethin D. Probst
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Chris Lattner) #3

Hi Ethin,

While it isn’t a pressing short term priority, I would like to see something to address the needs served by inline assembly in Swift at some point. We have a lot of experience from the Clang/C space to draw on here, and there are three general approaches supported by Clang:

1) “Processor Intrinsics" for instructions. Compilers for some architectures provide this as the only option (Itanium in MSVC IIRC).
2) “Microsoft” or “CodeWarrior” style inline assembly, like you show. This doesn’t require the developer to write register constraints, and sometimes allows direct use of local variables in the asm block.
3) “GCC” style inline assembly, which requires the user to write register constraints like “rmi”.

I’m significantly opposed to ever supporting GCC-style assembly, since it is very very common for developers to get the constraints wrong, and the compiler knows the instruction set anyway.

When it comes to #1 vs #2, there are tradeoffs:

#1 is simpler, doesn’t require language extensions (and can be done today by a sufficiently motivated person), and composes better with processor-independent intrinsics (like cross platform prefetch operations).

#2 is better for folks who “think in assembly”, because it has a more obvious and direct mapping to it. It has the additional downside of having to deal with multiple dialects of assembly, e.g. AT&T vs Intel syntax.

-Chris

···

On Dec 3, 2016, at 3:12 PM, Ethin Probst via swift-evolution <swift-evolution@swift.org> wrote:

Hello all,
My name is Ethin and I am new to this community. However, I certainly
am no newbie when it comes to software development, and have emailed
all of you to file a proposal of inline assembly in Swift. The
assembly language would be within an asm {...} block.


(Ethin Probst) #4

@Chris, I'm having trouble understanding your message. Do you mean
that you hope to implement this soon, or that you don't intend to?
@Félix, no, however I do think it would a good feature to have if you
need to optimize certain lines of code beyond preset optimizer passes.

···

On 12/3/16, Chris Lattner <clattner@apple.com> wrote:

On Dec 3, 2016, at 3:12 PM, Ethin Probst via swift-evolution >> <swift-evolution@swift.org> wrote:

Hello all,
My name is Ethin and I am new to this community. However, I certainly
am no newbie when it comes to software development, and have emailed
all of you to file a proposal of inline assembly in Swift. The
assembly language would be within an asm {...} block.

Hi Ethin,

While it isn’t a pressing short term priority, I would like to see something
to address the needs served by inline assembly in Swift at some point. We
have a lot of experience from the Clang/C space to draw on here, and there
are three general approaches supported by Clang:

1) “Processor Intrinsics" for instructions. Compilers for some
architectures provide this as the only option (Itanium in MSVC IIRC).
2) “Microsoft” or “CodeWarrior” style inline assembly, like you show. This
doesn’t require the developer to write register constraints, and sometimes
allows direct use of local variables in the asm block.
3) “GCC” style inline assembly, which requires the user to write register
constraints like “rmi”.

I’m significantly opposed to ever supporting GCC-style assembly, since it is
very very common for developers to get the constraints wrong, and the
compiler knows the instruction set anyway.

When it comes to #1 vs #2, there are tradeoffs:

#1 is simpler, doesn’t require language extensions (and can be done today by
a sufficiently motivated person), and composes better with
processor-independent intrinsics (like cross platform prefetch operations).

#2 is better for folks who “think in assembly”, because it has a more
obvious and direct mapping to it. It has the additional downside of having
to deal with multiple dialects of assembly, e.g. AT&T vs Intel syntax.

-Chris

--
Signed,
Ethin D. Probst


(Derrick Ho) #5

I feel like inline assembly is a very niche idea. Inline assembly is
supported by c and by extension objective-c.

//file.h
void aCFunction();
//file.m
void aCFunction() {
int a=10, b;
asm ("movl %1, %%eax;
movl %%eax, %0;"
:"=r"(b) /* output */
:"r"(a) /* input */
:"%eax" /* clobbered register */
);
}

I found the assembly code here:
http://www.ibiblio.org/gferg/ldp/GCC-Inline-Assembly-HOWTO.html

But theoretically you should be able to call this assembly code via
aCFunction() in swift.

I understand that it might be fun to do assembly in swift but I feel like
low level code should stay in its territory; if you want to do low level
programming write c code, if you want to go lower than that, leverage
inline assembly within the boundaries of c.

···

On Sat, Dec 3, 2016 at 7:23 PM Chris Lattner via swift-evolution < swift-evolution@swift.org> wrote:

> On Dec 3, 2016, at 3:12 PM, Ethin Probst via swift-evolution < > swift-evolution@swift.org> wrote:
>
> Hello all,
> My name is Ethin and I am new to this community. However, I certainly
> am no newbie when it comes to software development, and have emailed
> all of you to file a proposal of inline assembly in Swift. The
> assembly language would be within an asm {...} block.

Hi Ethin,

While it isn’t a pressing short term priority, I would like to see
something to address the needs served by inline assembly in Swift at some
point. We have a lot of experience from the Clang/C space to draw on here,
and there are three general approaches supported by Clang:

1) “Processor Intrinsics" for instructions. Compilers for some
architectures provide this as the only option (Itanium in MSVC IIRC).
2) “Microsoft” or “CodeWarrior” style inline assembly, like you show.
This doesn’t require the developer to write register constraints, and
sometimes allows direct use of local variables in the asm block.
3) “GCC” style inline assembly, which requires the user to write register
constraints like “rmi”.

I’m significantly opposed to ever supporting GCC-style assembly, since it
is very very common for developers to get the constraints wrong, and the
compiler knows the instruction set anyway.

When it comes to #1 vs #2, there are tradeoffs:

#1 is simpler, doesn’t require language extensions (and can be done today
by a sufficiently motivated person), and composes better with
processor-independent intrinsics (like cross platform prefetch operations).

#2 is better for folks who “think in assembly”, because it has a more
obvious and direct mapping to it. It has the additional downside of having
to deal with multiple dialects of assembly, e.g. AT&T vs Intel syntax.

-Chris

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Chris Lattner) #6

@Chris, I'm having trouble understanding your message. Do you mean
that you hope to implement this soon, or that you don't intend to?

I mean that inline assembly is niche and out of scope for swift 4 stage 1, but that I hope some future version of swift includes it. I have no plan to implement it.

-Chris

···

On Dec 3, 2016, at 6:42 PM, Ethin Probst <harlydavidsen@gmail.com> wrote:

@Félix, no, however I do think it would a good feature to have if you
need to optimize certain lines of code beyond preset optimizer passes.

On 12/3/16, Chris Lattner <clattner@apple.com> wrote:

On Dec 3, 2016, at 3:12 PM, Ethin Probst via swift-evolution >>> <swift-evolution@swift.org> wrote:

Hello all,
My name is Ethin and I am new to this community. However, I certainly
am no newbie when it comes to software development, and have emailed
all of you to file a proposal of inline assembly in Swift. The
assembly language would be within an asm {...} block.

Hi Ethin,

While it isn’t a pressing short term priority, I would like to see something
to address the needs served by inline assembly in Swift at some point. We
have a lot of experience from the Clang/C space to draw on here, and there
are three general approaches supported by Clang:

1) “Processor Intrinsics" for instructions. Compilers for some
architectures provide this as the only option (Itanium in MSVC IIRC).
2) “Microsoft” or “CodeWarrior” style inline assembly, like you show. This
doesn’t require the developer to write register constraints, and sometimes
allows direct use of local variables in the asm block.
3) “GCC” style inline assembly, which requires the user to write register
constraints like “rmi”.

I’m significantly opposed to ever supporting GCC-style assembly, since it is
very very common for developers to get the constraints wrong, and the
compiler knows the instruction set anyway.

When it comes to #1 vs #2, there are tradeoffs:

#1 is simpler, doesn’t require language extensions (and can be done today by
a sufficiently motivated person), and composes better with
processor-independent intrinsics (like cross platform prefetch operations).

#2 is better for folks who “think in assembly”, because it has a more
obvious and direct mapping to it. It has the additional downside of having
to deal with multiple dialects of assembly, e.g. AT&T vs Intel syntax.

-Chris

--
Signed,
Ethin D. Probst