Skip to content

Commit

Permalink
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
  • Loading branch information
frewsxcv authored Apr 6, 2017
2 parents 9e84bf8 + 57bd395 commit 99b81e5
Show file tree
Hide file tree
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
Expand Up @@ -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)
Expand Down
2 changes: 2 additions & 0 deletions src/doc/unstable-book/src/asm.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Up @@ -57,6 +57,8 @@ pub enum Def {
// Macro namespace
Macro(DefId, MacroKind),

GlobalAsm(DefId),

// Both namespaces
Err,
}
Expand Down Expand Up @@ -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
}

Expand Down Expand Up @@ -185,6 +188,7 @@ impl Def {
Def::Label(..) => "label",
Def::SelfTy(..) => "self type",
Def::Macro(..) => "macro",
Def::GlobalAsm(..) => "global asm",
Def::Err => "unresolved item",
}
}
Expand Down
3 changes: 3 additions & 0 deletions src/librustc/hir/intravisit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
8 changes: 8 additions & 0 deletions src/librustc/hir/lowering.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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_ {
Expand Down Expand Up @@ -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))
}
Expand Down
1 change: 1 addition & 0 deletions src/librustc/hir/map/def_collector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(..) => {}
Expand Down
1 change: 1 addition & 0 deletions src/librustc/hir/map/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
9 changes: 9 additions & 0 deletions src/librustc/hir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>,
Expand Down Expand Up @@ -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>}`
Expand Down Expand Up @@ -1718,6 +1726,7 @@ impl Item_ {
ItemFn(..) => "function",
ItemMod(..) => "module",
ItemForeignMod(..) => "foreign module",
ItemGlobalAsm(..) => "global asm",
ItemTy(..) => "type alias",
ItemEnum(..) => "enum",
ItemStruct(..) => "struct",
Expand Down
5 changes: 5 additions & 0 deletions src/librustc/hir/print.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)?;
Expand Down
3 changes: 2 additions & 1 deletion src/librustc/middle/reachable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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) => {
Expand Down
3 changes: 2 additions & 1 deletion src/librustc/middle/resolve_lifetime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
1 change: 1 addition & 0 deletions src/librustc_driver/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(..) |
Expand Down
5 changes: 4 additions & 1 deletion src/librustc_incremental/calculate_svh/svh_visitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,7 @@ enum SawItemComponent {
SawItemFn(Unsafety, Constness, Abi),
SawItemMod,
SawItemForeignMod(Abi),
SawItemGlobalAsm,
SawItemTy,
SawItemEnum,
SawItemStruct,
Expand All @@ -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,
Expand Down Expand Up @@ -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());
}
Expand Down
1 change: 1 addition & 0 deletions src/librustc_llvm/ffi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions src/librustc_metadata/decoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(_) |
Expand Down
2 changes: 2 additions & 0 deletions src/librustc_metadata/encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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, _) => {
Expand Down Expand Up @@ -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(..) |
Expand Down
1 change: 1 addition & 0 deletions src/librustc_metadata/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,7 @@ pub enum EntryKind<'tcx> {
ForeignImmStatic,
ForeignMutStatic,
ForeignMod,
GlobalAsm,
Type,
Enum(ReprOptions),
Field,
Expand Down
13 changes: 11 additions & 2 deletions src/librustc_privacy/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 }
}
};
Expand Down Expand Up @@ -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
Expand All @@ -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(..) => {
Expand Down Expand Up @@ -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(..) => {
Expand Down
2 changes: 2 additions & 0 deletions src/librustc_resolve/build_reduced_graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(..) => {
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_resolve/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

Expand Down
1 change: 1 addition & 0 deletions src/librustc_save_analysis/dump_visitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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: {:?}",
Expand Down
1 change: 1 addition & 0 deletions src/librustc_save_analysis/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -701,6 +701,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
Def::SelfTy(..) |
Def::Label(..) |
Def::Macro(..) |
Def::GlobalAsm(..) |
Def::Err => None,
}
}
Expand Down
8 changes: 8 additions & 0 deletions src/librustc_trans/asm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.