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
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
18 changes: 15 additions & 3 deletions src/librustc/lib/llvm.rs
Expand Up @@ -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;
Expand Down Expand Up @@ -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};

Expand Down Expand Up @@ -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;
}
}

Expand Down
6 changes: 4 additions & 2 deletions src/librustc/middle/liveness.rs
Expand Up @@ -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);
}
}
Expand Down Expand Up @@ -1345,6 +1346,7 @@ pub impl Liveness {
self.propagate_through_expr(e, succ)
}

expr_inline_asm(*) |
expr_lit(*) => {
succ
}
Expand Down Expand Up @@ -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);
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/middle/mem_categorization.rs
Expand Up @@ -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);
}
}
Expand Down
3 changes: 2 additions & 1 deletion src/librustc/middle/moves.rs
Expand Up @@ -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);
Expand Down
23 changes: 21 additions & 2 deletions src/librustc/middle/trans/build.rs
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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 {
Expand Down
11 changes: 11 additions & 0 deletions src/librustc/middle/trans/expr.rs
Expand Up @@ -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,
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/middle/trans/type_use.rs
Expand Up @@ -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(*) => ()
}
}

Expand Down
1 change: 1 addition & 0 deletions src/librustc/middle/ty.rs
Expand Up @@ -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) |
Expand Down
4 changes: 4 additions & 0 deletions src/librustc/middle/typeck/check/mod.rs
Expand Up @@ -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; }
Expand Down
1 change: 1 addition & 0 deletions src/librustc/middle/typeck/check/regionck.rs
Expand Up @@ -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(*) |
Expand Down
3 changes: 3 additions & 0 deletions src/libsyntax/ast.rs
Expand Up @@ -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.
Expand Down
174 changes: 174 additions & 0 deletions src/libsyntax/ext/asm.rs
@@ -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:
//
2 changes: 2 additions & 0 deletions src/libsyntax/ext/base.rs
Expand Up @@ -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));
Expand Down
1 change: 1 addition & 0 deletions src/libsyntax/fold.rs
Expand Up @@ -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(
Expand Down
2 changes: 1 addition & 1 deletion src/libsyntax/parse/parser.rs
Expand Up @@ -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};
Expand Down