Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Rollup merge of rust-lang#40702 - mrhota:global_asm, r=nagisa
Browse files Browse the repository at this point in the history
Implement global_asm!() (RFC 1548)

This is a first attempt. ~~One (potential) problem I haven't solved is how to handle multiple usages of `global_asm!` in a module/crate. It looks like `LLVMSetModuleInlineAsm` overwrites module asm, and `LLVMAppendModuleInlineAsm` is not provided in LLVM C headers 😦~~

I can provide more detail as needed, but honestly, there's not a lot going on here.

r? @eddyb

CC @Amanieu @jackpot51

Tracking issue: rust-lang#35119
frewsxcv authored Apr 6, 2017
2 parents 9e84bf8 + 57bd395 commit 99b81e5
Showing 48 changed files with 631 additions and 25 deletions.
1 change: 1 addition & 0 deletions src/doc/unstable-book/src/SUMMARY.md
Original file line number Diff line number Diff line change
@@ -81,6 +81,7 @@
- [future_atomic_orderings](future-atomic-orderings.md)
- [generic_param_attrs](generic-param-attrs.md)
- [get_type_id](get-type-id.md)
- [global_asm](global_asm.md)
- [heap_api](heap-api.md)
- [i128](i128.md)
- [i128_type](i128-type.md)
2 changes: 2 additions & 0 deletions src/doc/unstable-book/src/asm.md
Original file line number Diff line number Diff line change
@@ -189,3 +189,5 @@ constraints, etc.

[llvm-docs]: http://llvm.org/docs/LangRef.html#inline-assembler-expressions

If you need more power and don't mind losing some of the niceties of
`asm!`, check out [global_asm](global_asm.html).
78 changes: 78 additions & 0 deletions src/doc/unstable-book/src/global_asm.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# `global_asm`

The tracking issue for this feature is: [#35119]

[#35119]: https://github.com/rust-lang/rust/issues/35119

------------------------

The `global_asm!` macro allows the programmer to write arbitrary
assembly outside the scope of a function body, passing it through
`rustc` and `llvm` to the assembler. The macro is a no-frills
interface to LLVM's concept of [module-level inline assembly]. That is,
all caveats applicable to LLVM's module-level inline assembly apply
to `global_asm!`.

[module-level inline assembly]: http://llvm.org/docs/LangRef.html#module-level-inline-assembly

`global_asm!` fills a role not currently satisfied by either `asm!`
or `#[naked]` functions. The programmer has _all_ features of the
assembler at their disposal. The linker will expect to resolve any
symbols defined in the inline assembly, modulo any symbols marked as
external. It also means syntax for directives and assembly follow the
conventions of the assembler in your toolchain.

A simple usage looks like this:

```rust,ignore
# #![feature(global_asm)]
# you also need relevant target_arch cfgs
global_asm!(include_str!("something_neato.s"));
```

And a more complicated usage looks like this:

```rust,ignore
# #![feature(global_asm)]
# #![cfg(any(target_arch = "x86", target_arch = "x86_64"))]
pub mod sally {
global_asm!(r#"
.global foo
foo:
jmp baz
"#);
#[no_mangle]
pub unsafe extern "C" fn baz() {}
}
// the symbols `foo` and `bar` are global, no matter where
// `global_asm!` was used.
extern "C" {
fn foo();
fn bar();
}
pub mod harry {
global_asm!(r#"
.global bar
bar:
jmp quux
"#);
#[no_mangle]
pub unsafe extern "C" fn quux() {}
}
```

You may use `global_asm!` multiple times, anywhere in your crate, in
whatever way suits you. The effect is as if you concatenated all
usages and placed the larger, single usage in the crate root.

------------------------

If you don't need quite as much power and flexibility as
`global_asm!` provides, and you don't mind restricting your inline
assembly to `fn` bodies only, you might try the [asm](asm.html)
feature instead.
6 changes: 5 additions & 1 deletion src/librustc/hir/def.rs
Original file line number Diff line number Diff line change
@@ -57,6 +57,8 @@ pub enum Def {
// Macro namespace
Macro(DefId, MacroKind),

GlobalAsm(DefId),

// Both namespaces
Err,
}
@@ -144,7 +146,8 @@ impl Def {
Def::Variant(id) | Def::VariantCtor(id, ..) | Def::Enum(id) | Def::TyAlias(id) |
Def::AssociatedTy(id) | Def::TyParam(id) | Def::Struct(id) | Def::StructCtor(id, ..) |
Def::Union(id) | Def::Trait(id) | Def::Method(id) | Def::Const(id) |
Def::AssociatedConst(id) | Def::Local(id) | Def::Upvar(id, ..) | Def::Macro(id, ..) => {
Def::AssociatedConst(id) | Def::Local(id) | Def::Upvar(id, ..) | Def::Macro(id, ..) |
Def::GlobalAsm(id) => {
id
}

@@ -185,6 +188,7 @@ impl Def {
Def::Label(..) => "label",
Def::SelfTy(..) => "self type",
Def::Macro(..) => "macro",
Def::GlobalAsm(..) => "global asm",
Def::Err => "unresolved item",
}
}
3 changes: 3 additions & 0 deletions src/librustc/hir/intravisit.rs
Original file line number Diff line number Diff line change
@@ -474,6 +474,9 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) {
visitor.visit_id(item.id);
walk_list!(visitor, visit_foreign_item, &foreign_module.items);
}
ItemGlobalAsm(_) => {
visitor.visit_id(item.id);
}
ItemTy(ref typ, ref type_parameters) => {
visitor.visit_id(item.id);
visitor.visit_ty(typ);
8 changes: 8 additions & 0 deletions src/librustc/hir/lowering.rs
Original file line number Diff line number Diff line change
@@ -645,6 +645,13 @@ impl<'a> LoweringContext<'a> {
}
}

fn lower_global_asm(&mut self, ga: &GlobalAsm) -> P<hir::GlobalAsm> {
P(hir::GlobalAsm {
asm: ga.asm,
ctxt: ga.ctxt,
})
}

fn lower_variant(&mut self, v: &Variant) -> hir::Variant {
Spanned {
node: hir::Variant_ {
@@ -1287,6 +1294,7 @@ impl<'a> LoweringContext<'a> {
}
ItemKind::Mod(ref m) => hir::ItemMod(self.lower_mod(m)),
ItemKind::ForeignMod(ref nm) => hir::ItemForeignMod(self.lower_foreign_mod(nm)),
ItemKind::GlobalAsm(ref ga) => hir::ItemGlobalAsm(self.lower_global_asm(ga)),
ItemKind::Ty(ref t, ref generics) => {
hir::ItemTy(self.lower_ty(t), self.lower_generics(generics))
}
1 change: 1 addition & 0 deletions src/librustc/hir/map/def_collector.rs
Original file line number Diff line number Diff line change
@@ -120,6 +120,7 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
DefPathData::ValueNs(i.ident.name.as_str()),
ItemKind::MacroDef(..) => DefPathData::MacroDef(i.ident.name.as_str()),
ItemKind::Mac(..) => return self.visit_macro_invoc(i.id, false),
ItemKind::GlobalAsm(..) => DefPathData::Misc,
ItemKind::Use(ref view_path) => {
match view_path.node {
ViewPathGlob(..) => {}
1 change: 1 addition & 0 deletions src/librustc/hir/map/mod.rs
Original file line number Diff line number Diff line change
@@ -1056,6 +1056,7 @@ fn node_id_to_string(map: &Map, id: NodeId, include_id: bool) -> String {
ItemFn(..) => "fn",
ItemMod(..) => "mod",
ItemForeignMod(..) => "foreign mod",
ItemGlobalAsm(..) => "global asm",
ItemTy(..) => "ty",
ItemEnum(..) => "enum",
ItemStruct(..) => "struct",
9 changes: 9 additions & 0 deletions src/librustc/hir/mod.rs
Original file line number Diff line number Diff line change
@@ -1493,6 +1493,12 @@ pub struct ForeignMod {
pub items: HirVec<ForeignItem>,
}

#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub struct GlobalAsm {
pub asm: Symbol,
pub ctxt: SyntaxContext
}

#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub struct EnumDef {
pub variants: HirVec<Variant>,
@@ -1684,6 +1690,8 @@ pub enum Item_ {
ItemMod(Mod),
/// An external module
ItemForeignMod(ForeignMod),
/// Module-level inline assembly (from global_asm!)
ItemGlobalAsm(P<GlobalAsm>),
/// A type alias, e.g. `type Foo = Bar<u8>`
ItemTy(P<Ty>, Generics),
/// An enum definition, e.g. `enum Foo<A, B> {C<A>, D<B>}`
@@ -1718,6 +1726,7 @@ impl Item_ {
ItemFn(..) => "function",
ItemMod(..) => "module",
ItemForeignMod(..) => "foreign module",
ItemGlobalAsm(..) => "global asm",
ItemTy(..) => "type alias",
ItemEnum(..) => "enum",
ItemStruct(..) => "struct",
5 changes: 5 additions & 0 deletions src/librustc/hir/print.rs
Original file line number Diff line number Diff line change
@@ -630,6 +630,11 @@ impl<'a> State<'a> {
self.print_foreign_mod(nmod, &item.attrs)?;
self.bclose(item.span)?;
}
hir::ItemGlobalAsm(ref ga) => {
self.head(&visibility_qualified(&item.vis, "global asm"))?;
word(&mut self.s, &ga.asm.as_str())?;
self.end()?
}
hir::ItemTy(ref ty, ref params) => {
self.ibox(indent_unit)?;
self.ibox(0)?;
3 changes: 2 additions & 1 deletion src/librustc/middle/reachable.rs
Original file line number Diff line number Diff line change
@@ -267,7 +267,8 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> {
hir::ItemMod(..) | hir::ItemForeignMod(..) |
hir::ItemImpl(..) | hir::ItemTrait(..) |
hir::ItemStruct(..) | hir::ItemEnum(..) |
hir::ItemUnion(..) | hir::ItemDefaultImpl(..) => {}
hir::ItemUnion(..) | hir::ItemDefaultImpl(..) |
hir::ItemGlobalAsm(..) => {}
}
}
hir_map::NodeTraitItem(trait_method) => {
3 changes: 2 additions & 1 deletion src/librustc/middle/resolve_lifetime.rs
Original file line number Diff line number Diff line change
@@ -314,7 +314,8 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
hir::ItemUse(..) |
hir::ItemMod(..) |
hir::ItemDefaultImpl(..) |
hir::ItemForeignMod(..) => {
hir::ItemForeignMod(..) |
hir::ItemGlobalAsm(..) => {
// These sorts of items have no lifetime parameters at all.
intravisit::walk_item(self, item);
}
1 change: 1 addition & 0 deletions src/librustc_driver/test.rs
Original file line number Diff line number Diff line change
@@ -233,6 +233,7 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> {
hir::ItemStatic(..) |
hir::ItemFn(..) |
hir::ItemForeignMod(..) |
hir::ItemGlobalAsm(..) |
hir::ItemTy(..) => None,

hir::ItemEnum(..) |
5 changes: 4 additions & 1 deletion src/librustc_incremental/calculate_svh/svh_visitor.rs
Original file line number Diff line number Diff line change
@@ -354,6 +354,7 @@ enum SawItemComponent {
SawItemFn(Unsafety, Constness, Abi),
SawItemMod,
SawItemForeignMod(Abi),
SawItemGlobalAsm,
SawItemTy,
SawItemEnum,
SawItemStruct,
@@ -372,6 +373,7 @@ fn saw_item(node: &Item_) -> SawItemComponent {
ItemFn(_, unsafety, constness, abi, _, _) => SawItemFn(unsafety, constness, abi),
ItemMod(..) => SawItemMod,
ItemForeignMod(ref fm) => SawItemForeignMod(fm.abi),
ItemGlobalAsm(..) => SawItemGlobalAsm,
ItemTy(..) => SawItemTy,
ItemEnum(..) => SawItemEnum,
ItemStruct(..) => SawItemStruct,
@@ -920,7 +922,8 @@ impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> {
Def::AssociatedConst(..) |
Def::Local(..) |
Def::Upvar(..) |
Def::Macro(..) => {
Def::Macro(..) |
Def::GlobalAsm(..) => {
DefHash::SawDefId.hash(self.st);
self.hash_def_id(def.def_id());
}
1 change: 1 addition & 0 deletions src/librustc_llvm/ffi.rs
Original file line number Diff line number Diff line change
@@ -507,6 +507,7 @@ extern "C" {

/// See Module::setModuleInlineAsm.
pub fn LLVMSetModuleInlineAsm(M: ModuleRef, Asm: *const c_char);
pub fn LLVMRustAppendModuleInlineAsm(M: ModuleRef, Asm: *const c_char);

/// See llvm::LLVMTypeKind::getTypeID.
pub fn LLVMRustGetTypeKind(Ty: TypeRef) -> TypeKind;
1 change: 1 addition & 0 deletions src/librustc_metadata/decoder.rs
Original file line number Diff line number Diff line change
@@ -429,6 +429,7 @@ impl<'tcx> EntryKind<'tcx> {
EntryKind::Trait(_) => Def::Trait(did),
EntryKind::Enum(..) => Def::Enum(did),
EntryKind::MacroDef(_) => Def::Macro(did, MacroKind::Bang),
EntryKind::GlobalAsm => Def::GlobalAsm(did),

EntryKind::ForeignMod |
EntryKind::Impl(_) |
2 changes: 2 additions & 0 deletions src/librustc_metadata/encoder.rs
Original file line number Diff line number Diff line change
@@ -655,6 +655,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
return self.encode_info_for_mod(FromId(item.id, (m, &item.attrs, &item.vis)));
}
hir::ItemForeignMod(_) => EntryKind::ForeignMod,
hir::ItemGlobalAsm(..) => EntryKind::GlobalAsm,
hir::ItemTy(..) => EntryKind::Type,
hir::ItemEnum(..) => EntryKind::Enum(get_repr_options(&tcx, def_id)),
hir::ItemStruct(ref struct_def, _) => {
@@ -895,6 +896,7 @@ impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> {
hir::ItemFn(..) |
hir::ItemMod(..) |
hir::ItemForeignMod(..) |
hir::ItemGlobalAsm(..) |
hir::ItemExternCrate(..) |
hir::ItemUse(..) |
hir::ItemDefaultImpl(..) |
1 change: 1 addition & 0 deletions src/librustc_metadata/schema.rs
Original file line number Diff line number Diff line change
@@ -227,6 +227,7 @@ pub enum EntryKind<'tcx> {
ForeignImmStatic,
ForeignMutStatic,
ForeignMod,
GlobalAsm,
Type,
Enum(ReprOptions),
Field,
13 changes: 11 additions & 2 deletions src/librustc_privacy/lib.rs
Original file line number Diff line number Diff line change
@@ -160,7 +160,10 @@ impl<'a, 'tcx> Visitor<'tcx> for EmbargoVisitor<'a, 'tcx> {
self.prev_level
}
// Other `pub` items inherit levels from parents
_ => {
hir::ItemConst(..) | hir::ItemEnum(..) | hir::ItemExternCrate(..) |
hir::ItemGlobalAsm(..) | hir::ItemFn(..) | hir::ItemMod(..) |
hir::ItemStatic(..) | hir::ItemStruct(..) | hir::ItemTrait(..) |
hir::ItemTy(..) | hir::ItemUnion(..) | hir::ItemUse(..) => {
if item.vis == hir::Public { self.prev_level } else { None }
}
};
@@ -212,7 +215,9 @@ impl<'a, 'tcx> Visitor<'tcx> for EmbargoVisitor<'a, 'tcx> {
}
}
}
_ => {}
hir::ItemUse(..) | hir::ItemStatic(..) | hir::ItemConst(..) |
hir::ItemGlobalAsm(..) | hir::ItemTy(..) | hir::ItemMod(..) |
hir::ItemFn(..) | hir::ItemExternCrate(..) | hir::ItemDefaultImpl(..) => {}
}

// Mark all items in interfaces of reachable items as reachable
@@ -225,6 +230,8 @@ impl<'a, 'tcx> Visitor<'tcx> for EmbargoVisitor<'a, 'tcx> {
hir::ItemUse(..) => {}
// The interface is empty
hir::ItemDefaultImpl(..) => {}
// The interface is empty
hir::ItemGlobalAsm(..) => {}
// Visit everything
hir::ItemConst(..) | hir::ItemStatic(..) |
hir::ItemFn(..) | hir::ItemTy(..) => {
@@ -1092,6 +1099,8 @@ impl<'a, 'tcx> Visitor<'tcx> for PrivateItemsInPublicInterfacesVisitor<'a, 'tcx>
hir::ItemMod(..) => {}
// Checked in resolve
hir::ItemUse(..) => {}
// No subitems
hir::ItemGlobalAsm(..) => {}
// Subitems of these items have inherited publicity
hir::ItemConst(..) | hir::ItemStatic(..) | hir::ItemFn(..) |
hir::ItemTy(..) => {
2 changes: 2 additions & 0 deletions src/librustc_resolve/build_reduced_graph.rs
Original file line number Diff line number Diff line change
@@ -268,6 +268,8 @@ impl<'a> Resolver<'a> {
self.define(parent, ident, TypeNS, imported_binding);
}

ItemKind::GlobalAsm(..) => {}

ItemKind::Mod(..) if item.ident == keywords::Invalid.ident() => {} // Crate root

ItemKind::Mod(..) => {
2 changes: 1 addition & 1 deletion src/librustc_resolve/lib.rs
Original file line number Diff line number Diff line change
@@ -1707,7 +1707,7 @@ impl<'a> Resolver<'a> {
}
}

ItemKind::ExternCrate(_) | ItemKind::MacroDef(..) => {
ItemKind::ExternCrate(_) | ItemKind::MacroDef(..) | ItemKind::GlobalAsm(_)=> {
// do nothing, these are just around to be encoded
}

1 change: 1 addition & 0 deletions src/librustc_save_analysis/dump_visitor.rs
Original file line number Diff line number Diff line change
@@ -341,6 +341,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
Def::AssociatedTy(..) |
Def::AssociatedConst(..) |
Def::PrimTy(_) |
Def::GlobalAsm(_) |
Def::Err => {
span_bug!(span,
"process_def_kind for unexpected item: {:?}",
1 change: 1 addition & 0 deletions src/librustc_save_analysis/lib.rs
Original file line number Diff line number Diff line change
@@ -701,6 +701,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
Def::SelfTy(..) |
Def::Label(..) |
Def::Macro(..) |
Def::GlobalAsm(..) |
Def::Err => None,
}
}
8 changes: 8 additions & 0 deletions src/librustc_trans/asm.rs
Original file line number Diff line number Diff line change
@@ -124,3 +124,11 @@ pub fn trans_inline_asm<'a, 'tcx>(
llvm::LLVMMDNodeInContext(bcx.ccx.llcx(), &val, 1));
}
}

pub fn trans_global_asm<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
ga: &hir::GlobalAsm) {
let asm = CString::new(ga.asm.as_str().as_bytes()).unwrap();
unsafe {
llvm::LLVMRustAppendModuleInlineAsm(ccx.llmod(), asm.as_ptr());
}
}
Loading

0 comments on commit 99b81e5

Please sign in to comment.