Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Inline assembly #5317

Closed
wants to merge 8 commits into from
Closed

Inline assembly #5317

wants to merge 8 commits into from

Conversation

luqmana
Copy link
Member

@luqmana luqmana commented Mar 11, 2013

Issue #98.

#[cfg(target_os = "macos")]
fn helloworld() {
    unsafe {
        asm!(".pushsection __RODATA, __rodata
                  msg: .asciz \"Hello World!\"
              .popsection
              lea msg(%rip), %rdi
              call _puts");
    }
}

#[cfg(target_os = "linux")]
fn helloworld() {
    unsafe {
        asm!(".pushsection .rodata
                  msg: .asciz \"Hello World!\"
              .popsection
              lea msg(%rip), %rdi
              call puts");
    }
}

fn main() {
    helloworld();
}
% rustc foo.rs
% ./foo
Hello World!

@graydon
Copy link
Contributor

graydon commented Mar 11, 2013

This is awesome.

@pcwalton
Copy link
Contributor

This is actually quite useful for stack switching.

pub fn InlineAsmCall(cx: block, asm: *c_char, cons: *c_char,
dia: AsmDialect) -> ValueRef {
unsafe {
count_insn(cx, "inlineasm");

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not a smart Compiler or Rust hacker but I'm too curious to let this go. Is count_insn effectively a nop here? If not, how is the space required for the generated assembly calculated without count_insn being passed asm?

llfty seems to be a function stub for the inline assembly and v should be the bytevector returned by LLVM's assembler. The fact that the majority of this patch is readable to a noob like myself is great fun. And feel free to ignore, I know you guys have lots more important things to do. :)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe count_insn is just for some stats. Running rustc -Z count-llvm-insns will give you some counts of where LLVM insns originate.

Yes, llfty is the "type" of the inline assembly. Right now it's just a void return type with no input args since I haven't actually added the things necessary to make it take input and output operands.

@luqmana
Copy link
Member Author

luqmana commented Mar 12, 2013

So it can now parse it more or less like gcc/clang (though it doesn't actually do anything with input/output operands yet):

asm!( assembler template      // literal string
       : output operands      // optional, format: "constraint1"(expr1), "constraint2"(expr2), etc
       : input operands     // optional, format: "constraint1"(expr1), "constraint2"(expr2), etc
       : clobbers            // optional, format: "%eax", "%ebx", "memory", etc
       : options             // optional, comma separated strings
       );

The options bit is not something in gcc or clang. It's just a way to specify some extra keywords to LLVM about the assembly. Right now the only ones are volatile and alignstack. volatile is essentially analogous to __asm__ __volatile__ ( ... ); it signals the sideeffect keyword to LLVM.

For alignstack, from the LLVM manual:

In some cases inline asms will contain code that will not work unless the stack is aligned in 
some way, such as calls or SSE instructions on x86, yet will not contain code that does that
alignment within the asm. The compiler should make conservative assumptions about what
the asm might contain and should generate its usual stack alignment code in the prologue if
the ‘alignstack‘ keyword is present.

bors added a commit that referenced this pull request Mar 12, 2013
```Rust
#[cfg(target_os = "macos")]
fn helloworld() {
    unsafe {
        asm!(".pushsection __RODATA, __rodata
                  msg: .asciz \"Hello World!\"
              .popsection
              movq msg@GOTPCREL(%rip), %rdi
              call _puts");
    }
}

#[cfg(target_os = "linux")]
fn helloworld() {
    unsafe {
        asm!(".pushsection .rodata
                  msg: .asciz \"Hello World!\"
              .popsection
              movq msg@GOTPCREL(%rip), %rdi
              call puts");
    }
}

fn main() {
    helloworld();
}
```

```
% rustc foo.rs
% ./foo
Hello World!
```
@bors bors closed this Mar 12, 2013
@luqmana luqmana mentioned this pull request Mar 13, 2013
@z0w0 z0w0 mentioned this pull request Mar 14, 2013
bors added a commit that referenced this pull request Mar 16, 2013
Continuation of #5317. Actually use operands properly now, including any number of output operands.

Which means you can do things like call printf:
```Rust
fn main() {
    unsafe {
        do str::as_c_str(~"The answer is %d.\n") |c| {
            let a = 42;
            asm!("mov $0, %rdi\n\t\
                  mov $1, %rsi\n\t\
                  xorl %eax, %eax\n\t\
                  call _printf"
                 :
                 : "r"(c), "r"(a)
                 : "rdi", "rsi", "eax"
                 : "volatile","alignstack"
                 );
        }
    }
}
```

```
% rustc foo.rs
% ./foo
The answer is 42.
```

Or just add 2 numbers:
```Rust
fn add(a: int, b: int) -> int {
    let mut c = 0;
    unsafe {
        asm!("add $2, $0"
             : "=r"(c)
             : "0"(a), "r"(b)
             );
    }
    c
}

fn main() {
    io::println(fmt!("%d", add(1, 2)));
}
```

```
% rustc foo.rs
% ./foo
3
```

Multiple outputs!
```Rust
fn addsub(a: int, b: int) -> (int, int) {
    let mut c = 0;
    let mut d = 0;
    unsafe {
        asm!("add $4, $0\n\t\
              sub $4, $1"
             : "=r"(c), "=r"(d)
             : "0"(a), "1"(a), "r"(b)
             );
    }
    (c, d)
}

fn main() {
    io::println(fmt!("%?", addsub(5, 1)));
}
```
```
% rustc foo.rs
% ./foo
(6, 4)
```

This also classifies inline asm as RvalueStmtExpr instead of the somewhat arbitrary kind I made it initially. There are a few XXX's regarding what to do in the liveness and move passes.
pczarn referenced this pull request in lexs/rust-os Feb 8, 2014
bors added a commit to rust-lang-ci/rust that referenced this pull request May 2, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants