auto merge of #5317 : luqmana/rust/inline-asm, r=graydon
```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! ```
This commit is contained in:
commit
34aaf350c2
@ -188,6 +188,12 @@ pub enum Metadata {
|
||||
MD_tbaa_struct = 5
|
||||
}
|
||||
|
||||
// Inline Asm Dialect
|
||||
pub enum AsmDialect {
|
||||
AD_ATT = 0,
|
||||
AD_Intel = 1
|
||||
}
|
||||
|
||||
// Opaque pointer types
|
||||
pub enum Module_opaque {}
|
||||
pub type ModuleRef = *Module_opaque;
|
||||
@ -217,9 +223,9 @@ pub enum SectionIterator_opaque {}
|
||||
pub type SectionIteratorRef = *SectionIterator_opaque;
|
||||
|
||||
pub mod llvm {
|
||||
use super::{AtomicBinOp, AtomicOrdering, BasicBlockRef, Bool, BuilderRef};
|
||||
use super::{ContextRef, MemoryBufferRef, ModuleRef, ObjectFileRef};
|
||||
use super::{Opcode, PassManagerRef, PassManagerBuilderRef};
|
||||
use super::{AsmDialect, AtomicBinOp, AtomicOrdering, BasicBlockRef};
|
||||
use super::{Bool, BuilderRef, ContextRef, MemoryBufferRef, ModuleRef};
|
||||
use super::{ObjectFileRef, Opcode, PassManagerRef, PassManagerBuilderRef};
|
||||
use super::{SectionIteratorRef, TargetDataRef, TypeKind, TypeRef, UseRef};
|
||||
use super::{ValueRef};
|
||||
|
||||
@ -1433,6 +1439,12 @@ pub mod llvm {
|
||||
|
||||
/** Enables LLVM debug output. */
|
||||
pub unsafe fn LLVMSetDebug(Enabled: c_int);
|
||||
|
||||
/** Prepares inline assembly. */
|
||||
pub unsafe fn LLVMInlineAsm(Ty: TypeRef, AsmString: *c_char,
|
||||
Constraints: *c_char, SideEffects: Bool,
|
||||
AlignStack: Bool, Dialect: AsmDialect)
|
||||
-> ValueRef;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -620,7 +620,8 @@ fn visit_expr(expr: @expr, &&self: @mut IrMaps, vt: vt<@mut IrMaps>) {
|
||||
expr_do_body(*) | expr_cast(*) | expr_unary(*) | expr_break(_) |
|
||||
expr_again(_) | expr_lit(_) | expr_ret(*) | expr_block(*) |
|
||||
expr_assign(*) | expr_swap(*) | expr_assign_op(*) | expr_mac(*) |
|
||||
expr_struct(*) | expr_repeat(*) | expr_paren(*) => {
|
||||
expr_struct(*) | expr_repeat(*) | expr_paren(*) |
|
||||
expr_inline_asm(*) => {
|
||||
visit::visit_expr(expr, self, vt);
|
||||
}
|
||||
}
|
||||
@ -1345,6 +1346,7 @@ pub impl Liveness {
|
||||
self.propagate_through_expr(e, succ)
|
||||
}
|
||||
|
||||
expr_inline_asm(*) |
|
||||
expr_lit(*) => {
|
||||
succ
|
||||
}
|
||||
@ -1618,7 +1620,7 @@ fn check_expr(expr: @expr, &&self: @Liveness, vt: vt<@Liveness>) {
|
||||
expr_cast(*) | expr_unary(*) | expr_ret(*) | expr_break(*) |
|
||||
expr_again(*) | expr_lit(_) | expr_block(*) | expr_swap(*) |
|
||||
expr_mac(*) | expr_addr_of(*) | expr_struct(*) | expr_repeat(*) |
|
||||
expr_paren(*) => {
|
||||
expr_paren(*) | expr_inline_asm(*) => {
|
||||
visit::visit_expr(expr, self, vt);
|
||||
}
|
||||
}
|
||||
|
@ -447,7 +447,7 @@ pub impl mem_categorization_ctxt {
|
||||
ast::expr_while(*) | ast::expr_block(*) | ast::expr_loop(*) |
|
||||
ast::expr_match(*) | ast::expr_lit(*) | ast::expr_break(*) |
|
||||
ast::expr_mac(*) | ast::expr_again(*) | ast::expr_struct(*) |
|
||||
ast::expr_repeat(*) => {
|
||||
ast::expr_repeat(*) | ast::expr_inline_asm(*) => {
|
||||
return self.cat_rvalue(expr, expr_ty);
|
||||
}
|
||||
}
|
||||
|
@ -560,7 +560,8 @@ pub impl VisitContext {
|
||||
|
||||
expr_break(*) |
|
||||
expr_again(*) |
|
||||
expr_lit(*) => {}
|
||||
expr_lit(*) |
|
||||
expr_inline_asm(*) => {}
|
||||
|
||||
expr_loop(ref blk, _) => {
|
||||
self.consume_block(blk, visitor);
|
||||
|
@ -9,7 +9,7 @@
|
||||
// except according to those terms.
|
||||
|
||||
use lib::llvm::llvm;
|
||||
use lib::llvm::{CallConv, TypeKind, AtomicBinOp, AtomicOrdering};
|
||||
use lib::llvm::{CallConv, TypeKind, AtomicBinOp, AtomicOrdering, AsmDialect};
|
||||
use lib::llvm::{Opcode, IntPredicate, RealPredicate, True, False};
|
||||
use lib::llvm::{ValueRef, TypeRef, BasicBlockRef, BuilderRef, ModuleRef};
|
||||
use lib;
|
||||
@ -18,7 +18,7 @@ use syntax::codemap::span;
|
||||
|
||||
use core::prelude::*;
|
||||
use core::cast;
|
||||
use core::libc::{c_uint, c_int, c_ulonglong};
|
||||
use core::libc::{c_uint, c_int, c_ulonglong, c_char};
|
||||
use core::libc;
|
||||
use core::option::Some;
|
||||
use core::ptr;
|
||||
@ -872,6 +872,25 @@ pub fn add_comment(bcx: block, text: &str) {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn InlineAsmCall(cx: block, asm: *c_char, cons: *c_char,
|
||||
volatile: bool, alignstack: bool,
|
||||
dia: AsmDialect) -> ValueRef {
|
||||
unsafe {
|
||||
count_insn(cx, "inlineasm");
|
||||
|
||||
let volatile = if volatile { lib::llvm::True }
|
||||
else { lib::llvm::False };
|
||||
let alignstack = if alignstack { lib::llvm::True }
|
||||
else { lib::llvm::False };
|
||||
|
||||
let llfty = T_fn(~[], T_void());
|
||||
let v = llvm::LLVMInlineAsm(llfty, asm, cons, volatile,
|
||||
alignstack, dia);
|
||||
|
||||
Call(cx, v, ~[])
|
||||
}
|
||||
}
|
||||
|
||||
pub fn Call(cx: block, Fn: ValueRef, Args: &[ValueRef]) -> ValueRef {
|
||||
if cx.unreachable { return _UndefReturn(cx, Fn); }
|
||||
unsafe {
|
||||
|
@ -691,6 +691,17 @@ fn trans_rvalue_dps_unadjusted(bcx: block, expr: @ast::expr,
|
||||
ast::expr_assign_op(op, dst, src) => {
|
||||
return trans_assign_op(bcx, expr, op, dst, src);
|
||||
}
|
||||
ast::expr_inline_asm(asm, cons, volatile, alignstack) => {
|
||||
// XXX: cons doesn't actual contain ALL the stuff we should
|
||||
// be passing since the constraints for in/outputs aren't included
|
||||
do str::as_c_str(*asm) |a| {
|
||||
do str::as_c_str(*cons) |c| {
|
||||
InlineAsmCall(bcx, a, c, volatile, alignstack,
|
||||
lib::llvm::AD_ATT);
|
||||
}
|
||||
}
|
||||
return bcx;
|
||||
}
|
||||
_ => {
|
||||
bcx.tcx().sess.span_bug(
|
||||
expr.span,
|
||||
|
@ -353,7 +353,7 @@ pub fn mark_for_expr(cx: Context, e: @expr) {
|
||||
expr_match(*) | expr_block(_) | expr_if(*) | expr_while(*) |
|
||||
expr_break(_) | expr_again(_) | expr_unary(_, _) | expr_lit(_) |
|
||||
expr_mac(_) | expr_addr_of(_, _) | expr_ret(_) | expr_loop(_, _) |
|
||||
expr_loop_body(_) | expr_do_body(_) => ()
|
||||
expr_loop_body(_) | expr_do_body(_) | expr_inline_asm(*) => ()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3076,6 +3076,7 @@ pub fn expr_kind(tcx: ctxt,
|
||||
ast::expr_block(*) |
|
||||
ast::expr_copy(*) |
|
||||
ast::expr_repeat(*) |
|
||||
ast::expr_inline_asm(*) |
|
||||
ast::expr_lit(@codemap::spanned {node: lit_str(_), _}) |
|
||||
ast::expr_vstore(_, ast::expr_vstore_slice) |
|
||||
ast::expr_vstore(_, ast::expr_vstore_mut_slice) |
|
||||
|
@ -2303,6 +2303,10 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt,
|
||||
let region_lb = ty::re_scope(expr.id);
|
||||
instantiate_path(fcx, pth, tpt, expr.span, expr.id, region_lb);
|
||||
}
|
||||
ast::expr_inline_asm(*) => {
|
||||
fcx.require_unsafe(expr.span, ~"use of inline assembly");
|
||||
fcx.write_nil(id);
|
||||
}
|
||||
ast::expr_mac(_) => tcx.sess.bug(~"unexpanded macro"),
|
||||
ast::expr_break(_) => { fcx.write_bot(id); bot = true; }
|
||||
ast::expr_again(_) => { fcx.write_bot(id); bot = true; }
|
||||
|
@ -682,6 +682,7 @@ pub mod guarantor {
|
||||
|
||||
// All of these expressions are rvalues and hence their
|
||||
// value is not guaranteed by a region pointer.
|
||||
ast::expr_inline_asm(*) |
|
||||
ast::expr_mac(*) |
|
||||
ast::expr_lit(_) |
|
||||
ast::expr_unary(*) |
|
||||
|
@ -601,6 +601,9 @@ pub enum expr_ {
|
||||
expr_ret(Option<@expr>),
|
||||
expr_log(log_level, @expr, @expr),
|
||||
|
||||
/* asm, clobbers + constraints, volatile, align stack */
|
||||
expr_inline_asm(@~str, @~str, bool, bool),
|
||||
|
||||
expr_mac(mac),
|
||||
|
||||
// A struct literal expression.
|
||||
|
174
src/libsyntax/ext/asm.rs
Normal file
174
src/libsyntax/ext/asm.rs
Normal file
@ -0,0 +1,174 @@
|
||||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Inline assembly support.
|
||||
*/
|
||||
|
||||
use core::prelude::*;
|
||||
|
||||
use ast;
|
||||
use codemap::span;
|
||||
use ext::base;
|
||||
use ext::base::*;
|
||||
use parse;
|
||||
use parse::token;
|
||||
|
||||
enum State {
|
||||
Asm,
|
||||
Outputs,
|
||||
Inputs,
|
||||
Clobbers,
|
||||
Options
|
||||
}
|
||||
|
||||
fn next_state(s: State) -> Option<State> {
|
||||
match s {
|
||||
Asm => Some(Outputs),
|
||||
Outputs => Some(Inputs),
|
||||
Inputs => Some(Clobbers),
|
||||
Clobbers => Some(Options),
|
||||
Options => None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn expand_asm(cx: ext_ctxt, sp: span, tts: &[ast::token_tree])
|
||||
-> base::MacResult {
|
||||
|
||||
let p = parse::new_parser_from_tts(cx.parse_sess(), cx.cfg(),
|
||||
vec::from_slice(tts));
|
||||
|
||||
let mut asm = ~"";
|
||||
let mut outputs = ~[];
|
||||
let mut inputs = ~[];
|
||||
let mut cons = ~"";
|
||||
let mut volatile = false;
|
||||
let mut alignstack = false;
|
||||
|
||||
let mut state = Asm;
|
||||
loop outer: {
|
||||
match state {
|
||||
Asm => {
|
||||
asm = expr_to_str(cx, p.parse_expr(),
|
||||
~"inline assembly must be a string literal.");
|
||||
}
|
||||
Outputs => {
|
||||
while *p.token != token::EOF &&
|
||||
*p.token != token::COLON &&
|
||||
*p.token != token::MOD_SEP {
|
||||
|
||||
if outputs.len() != 0 {
|
||||
p.eat(&token::COMMA);
|
||||
}
|
||||
|
||||
let constraint = p.parse_str();
|
||||
p.expect(&token::LPAREN);
|
||||
let out = p.parse_expr();
|
||||
p.expect(&token::RPAREN);
|
||||
|
||||
outputs.push((constraint, out));
|
||||
}
|
||||
}
|
||||
Inputs => {
|
||||
while *p.token != token::EOF &&
|
||||
*p.token != token::COLON &&
|
||||
*p.token != token::MOD_SEP {
|
||||
|
||||
if inputs.len() != 0 {
|
||||
p.eat(&token::COMMA);
|
||||
}
|
||||
|
||||
let constraint = p.parse_str();
|
||||
p.expect(&token::LPAREN);
|
||||
let in = p.parse_expr();
|
||||
p.expect(&token::RPAREN);
|
||||
|
||||
inputs.push((constraint, in));
|
||||
}
|
||||
}
|
||||
Clobbers => {
|
||||
let mut clobs = ~[];
|
||||
while *p.token != token::EOF &&
|
||||
*p.token != token::COLON &&
|
||||
*p.token != token::MOD_SEP {
|
||||
|
||||
if clobs.len() != 0 {
|
||||
p.eat(&token::COMMA);
|
||||
}
|
||||
|
||||
let clob = ~"~{" + *p.parse_str() + ~"}";
|
||||
clobs.push(clob);
|
||||
}
|
||||
|
||||
cons = str::connect(clobs, ",");
|
||||
}
|
||||
Options => {
|
||||
let option = *p.parse_str();
|
||||
|
||||
if option == ~"volatile" {
|
||||
volatile = true;
|
||||
} else if option == ~"alignstack" {
|
||||
alignstack = true;
|
||||
}
|
||||
|
||||
if *p.token == token::COMMA {
|
||||
p.eat(&token::COMMA);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while *p.token == token::COLON ||
|
||||
*p.token == token::MOD_SEP ||
|
||||
*p.token == token::EOF {
|
||||
state = if *p.token == token::COLON {
|
||||
p.bump();
|
||||
match next_state(state) {
|
||||
Some(x) => x,
|
||||
None => break outer
|
||||
}
|
||||
} else if *p.token == token::MOD_SEP {
|
||||
p.bump();
|
||||
let s = match next_state(state) {
|
||||
Some(x) => x,
|
||||
None => break outer
|
||||
};
|
||||
match next_state(s) {
|
||||
Some(x) => x,
|
||||
None => break outer
|
||||
}
|
||||
} else if *p.token == token::EOF {
|
||||
break outer;
|
||||
} else {
|
||||
state
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
MRExpr(@ast::expr {
|
||||
id: cx.next_id(),
|
||||
callee_id: cx.next_id(),
|
||||
node: ast::expr_inline_asm(@asm, @cons, volatile, alignstack),
|
||||
span: sp
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
|
||||
//
|
||||
// Local Variables:
|
||||
// mode: rust
|
||||
// fill-column: 78;
|
||||
// indent-tabs-mode: nil
|
||||
// c-basic-offset: 4
|
||||
// buffer-file-coding-system: utf-8-unix
|
||||
// End:
|
||||
//
|
@ -198,6 +198,8 @@ pub fn syntax_expander_table() -> SyntaxEnv {
|
||||
ext::source_util::expand_mod));
|
||||
syntax_expanders.insert(@~"proto",
|
||||
builtin_item_tt(ext::pipes::expand_proto));
|
||||
syntax_expanders.insert(@~"asm",
|
||||
builtin_normal_tt(ext::asm::expand_asm));
|
||||
syntax_expanders.insert(
|
||||
@~"trace_macros",
|
||||
builtin_normal_tt(ext::trace_macros::expand_trace_macros));
|
||||
|
@ -560,6 +560,7 @@ pub fn noop_fold_expr(e: &expr_, fld: @ast_fold) -> expr_ {
|
||||
fld.fold_expr(e)
|
||||
)
|
||||
}
|
||||
expr_inline_asm(*) => copy *e,
|
||||
expr_mac(ref mac) => expr_mac(fold_mac((*mac))),
|
||||
expr_struct(path, ref fields, maybe_expr) => {
|
||||
expr_struct(
|
||||
|
@ -27,7 +27,7 @@ use ast::{expr_field, expr_fn_block, expr_if, expr_index};
|
||||
use ast::{expr_lit, expr_log, expr_loop, expr_loop_body, expr_mac};
|
||||
use ast::{expr_method_call, expr_paren, expr_path, expr_repeat};
|
||||
use ast::{expr_ret, expr_swap, expr_struct, expr_tup, expr_unary};
|
||||
use ast::{expr_vec, expr_vstore, expr_vstore_mut_box};
|
||||
use ast::{expr_vec, expr_vstore, expr_vstore_mut_box, expr_inline_asm};
|
||||
use ast::{expr_vstore_fixed, expr_vstore_slice, expr_vstore_box};
|
||||
use ast::{expr_vstore_mut_slice, expr_while, extern_fn, field, fn_decl};
|
||||
use ast::{expr_vstore_uniq, TyClosure, TyBareFn, Onceness, Once, Many};
|
||||
|
@ -1398,6 +1398,18 @@ pub fn print_expr(s: @ps, &&expr: @ast::expr) {
|
||||
}
|
||||
}
|
||||
}
|
||||
ast::expr_inline_asm(a, c, v, _) => {
|
||||
if v {
|
||||
word(s.s, ~"__volatile__ asm!");
|
||||
} else {
|
||||
word(s.s, ~"asm!");
|
||||
}
|
||||
popen(s);
|
||||
print_string(s, *a);
|
||||
word_space(s, ~",");
|
||||
print_string(s, *c);
|
||||
pclose(s);
|
||||
}
|
||||
ast::expr_mac(ref m) => print_mac(s, (*m)),
|
||||
ast::expr_paren(e) => {
|
||||
popen(s);
|
||||
|
@ -60,6 +60,7 @@ pub mod print {
|
||||
}
|
||||
|
||||
pub mod ext {
|
||||
pub mod asm;
|
||||
pub mod base;
|
||||
pub mod expand;
|
||||
|
||||
|
@ -562,6 +562,7 @@ pub fn visit_expr<E>(ex: @expr, e: E, v: vt<E>) {
|
||||
}
|
||||
expr_mac(ref mac) => visit_mac((*mac), e, v),
|
||||
expr_paren(x) => (v.visit_expr)(x, e, v),
|
||||
expr_inline_asm(*) => (),
|
||||
}
|
||||
(v.visit_expr_post)(ex, e, v);
|
||||
}
|
||||
|
@ -15,6 +15,7 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===
|
||||
|
||||
#include "llvm/InlineAsm.h"
|
||||
#include "llvm/LLVMContext.h"
|
||||
#include "llvm/Linker.h"
|
||||
#include "llvm/PassManager.h"
|
||||
@ -539,3 +540,14 @@ extern "C" void LLVMSetDebug(int Enabled) {
|
||||
DebugFlag = Enabled;
|
||||
#endif
|
||||
}
|
||||
|
||||
extern "C" LLVMValueRef LLVMInlineAsm(LLVMTypeRef Ty,
|
||||
char *AsmString,
|
||||
char *Constraints,
|
||||
LLVMBool HasSideEffects,
|
||||
LLVMBool IsAlignStack,
|
||||
InlineAsm::AsmDialect Dialect) {
|
||||
return wrap(InlineAsm::get(unwrap<FunctionType>(Ty), AsmString,
|
||||
Constraints, HasSideEffects,
|
||||
IsAlignStack, Dialect));
|
||||
}
|
||||
|
@ -583,3 +583,4 @@ LLVMX86MMXTypeInContext
|
||||
LLVMConstNamedStruct
|
||||
LLVMStructCreateNamed
|
||||
LLVMStructSetBody
|
||||
LLVMInlineAsm
|
||||
|
Loading…
x
Reference in New Issue
Block a user