diff --git a/src/doc/unstable-book/src/SUMMARY.md b/src/doc/unstable-book/src/SUMMARY.md index 9ce097e78a4e5..0d68f3ca4a843 100644 --- a/src/doc/unstable-book/src/SUMMARY.md +++ b/src/doc/unstable-book/src/SUMMARY.md @@ -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) diff --git a/src/doc/unstable-book/src/asm.md b/src/doc/unstable-book/src/asm.md index 032d9d8124026..5e68be633e7ab 100644 --- a/src/doc/unstable-book/src/asm.md +++ b/src/doc/unstable-book/src/asm.md @@ -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). diff --git a/src/doc/unstable-book/src/global_asm.md b/src/doc/unstable-book/src/global_asm.md new file mode 100644 index 0000000000000..44921aa309f84 --- /dev/null +++ b/src/doc/unstable-book/src/global_asm.md @@ -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. diff --git a/src/librustc/hir/def.rs b/src/librustc/hir/def.rs index 7bab4a8d725dc..771031db0c045 100644 --- a/src/librustc/hir/def.rs +++ b/src/librustc/hir/def.rs @@ -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", } } diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index c7ad143c94979..01f600bb1888f 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -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); diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 17185a6ab69f4..7e1b0d6389d2e 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -645,6 +645,13 @@ impl<'a> LoweringContext<'a> { } } + fn lower_global_asm(&mut self, ga: &GlobalAsm) -> P { + 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)) } diff --git a/src/librustc/hir/map/def_collector.rs b/src/librustc/hir/map/def_collector.rs index afdb9059ea7c0..9887f4560f312 100644 --- a/src/librustc/hir/map/def_collector.rs +++ b/src/librustc/hir/map/def_collector.rs @@ -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(..) => {} diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index d7aa36b24f942..2287b525df75f 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -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", diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index d5000ac9c1866..4d38b0eae1d5f 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -1493,6 +1493,12 @@ pub struct ForeignMod { pub items: HirVec, } +#[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, @@ -1684,6 +1690,8 @@ pub enum Item_ { ItemMod(Mod), /// An external module ItemForeignMod(ForeignMod), + /// Module-level inline assembly (from global_asm!) + ItemGlobalAsm(P), /// A type alias, e.g. `type Foo = Bar` ItemTy(P, Generics), /// An enum definition, e.g. `enum Foo {C, D}` @@ -1718,6 +1726,7 @@ impl Item_ { ItemFn(..) => "function", ItemMod(..) => "module", ItemForeignMod(..) => "foreign module", + ItemGlobalAsm(..) => "global asm", ItemTy(..) => "type alias", ItemEnum(..) => "enum", ItemStruct(..) => "struct", diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index 04a65fd5e3aa4..48efe1ad58f34 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -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)?; diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs index b0e39442af98c..30c60fb902010 100644 --- a/src/librustc/middle/reachable.rs +++ b/src/librustc/middle/reachable.rs @@ -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) => { diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index 8037570d24a80..b9938a04047c9 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -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); } diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index af2416f787ea4..44e291a44c777 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -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(..) | diff --git a/src/librustc_incremental/calculate_svh/svh_visitor.rs b/src/librustc_incremental/calculate_svh/svh_visitor.rs index 5401b371888e9..182fabed5cda3 100644 --- a/src/librustc_incremental/calculate_svh/svh_visitor.rs +++ b/src/librustc_incremental/calculate_svh/svh_visitor.rs @@ -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()); } diff --git a/src/librustc_llvm/ffi.rs b/src/librustc_llvm/ffi.rs index 32c9183ece999..402166cc13fd9 100644 --- a/src/librustc_llvm/ffi.rs +++ b/src/librustc_llvm/ffi.rs @@ -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; diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 43e076e799b3d..b893cccf8978b 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -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(_) | diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 38d774992a551..6b4c13439f72f 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -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(..) | diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs index abb482a50ebc2..bd50c1a3c97d3 100644 --- a/src/librustc_metadata/schema.rs +++ b/src/librustc_metadata/schema.rs @@ -227,6 +227,7 @@ pub enum EntryKind<'tcx> { ForeignImmStatic, ForeignMutStatic, ForeignMod, + GlobalAsm, Type, Enum(ReprOptions), Field, diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index 300848fe8f25e..92f7e48b6be48 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -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(..) => { diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index a15431afc164b..80f853778c744 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -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(..) => { diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 0466e76475da3..5cbced9738f70 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -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 } diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index 3fd0ce45e3610..3e8f7e11b6b43 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -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: {:?}", diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index 44615071a56a7..d822f7bea3a30 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -701,6 +701,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { Def::SelfTy(..) | Def::Label(..) | Def::Macro(..) | + Def::GlobalAsm(..) | Def::Err => None, } } diff --git a/src/librustc_trans/asm.rs b/src/librustc_trans/asm.rs index 3e270b7928ebc..92cbd004206e7 100644 --- a/src/librustc_trans/asm.rs +++ b/src/librustc_trans/asm.rs @@ -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()); + } +} diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index 500802a4135d0..ba2b807d5a01c 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -349,6 +349,9 @@ fn collect_items_rec<'a, 'tcx: 'a>(scx: &SharedCrateContext<'a, 'tcx>, collect_neighbours(scx, instance, &mut neighbors); } + TransItem::GlobalAsm(..) => { + recursion_depth_reset = None; + } } record_inlining_canditates(scx.tcx(), starting_point, &neighbors[..], inlining_map); @@ -840,6 +843,12 @@ impl<'b, 'a, 'v> ItemLikeVisitor<'v> for RootCollector<'b, 'a, 'v> { } } } + hir::ItemGlobalAsm(..) => { + debug!("RootCollector: ItemGlobalAsm({})", + def_id_to_string(self.scx.tcx(), + self.scx.tcx().hir.local_def_id(item.id))); + self.output.push(TransItem::GlobalAsm(item.id)); + } hir::ItemStatic(..) => { debug!("RootCollector: ItemStatic({})", def_id_to_string(self.scx.tcx(), diff --git a/src/librustc_trans/partitioning.rs b/src/librustc_trans/partitioning.rs index 90ce40cfbcf8f..4973181202eed 100644 --- a/src/librustc_trans/partitioning.rs +++ b/src/librustc_trans/partitioning.rs @@ -185,15 +185,16 @@ impl<'tcx> CodegenUnit<'tcx> { symbol_name.len().hash(&mut state); symbol_name.hash(&mut state); let exported = match item { - TransItem::Fn(ref instance) => { - let node_id = - scx.tcx().hir.as_local_node_id(instance.def_id()); + TransItem::Fn(ref instance) => { + let node_id = + scx.tcx().hir.as_local_node_id(instance.def_id()); node_id.map(|node_id| exported_symbols.contains(&node_id)) - .unwrap_or(false) - } - TransItem::Static(node_id) => { + .unwrap_or(false) + } + TransItem::Static(node_id) => { exported_symbols.contains(&node_id) - } + } + TransItem::GlobalAsm(..) => true, }; exported.hash(&mut state); } @@ -243,7 +244,9 @@ impl<'tcx> CodegenUnit<'tcx> { TransItem::Fn(instance) => { tcx.hir.as_local_node_id(instance.def_id()) } - TransItem::Static(node_id) => Some(node_id), + TransItem::Static(node_id) | TransItem::GlobalAsm(node_id) => { + Some(node_id) + } } } } @@ -338,7 +341,8 @@ fn place_root_translation_items<'a, 'tcx, I>(scx: &SharedCrateContext<'a, 'tcx>, None => { match trans_item { TransItem::Fn(..) | - TransItem::Static(..) => llvm::ExternalLinkage, + TransItem::Static(..) | + TransItem::GlobalAsm(..) => llvm::ExternalLinkage, } } }; @@ -483,7 +487,8 @@ fn characteristic_def_id_of_trans_item<'a, 'tcx>(scx: &SharedCrateContext<'a, 't Some(def_id) } - TransItem::Static(node_id) => Some(tcx.hir.local_def_id(node_id)), + TransItem::Static(node_id) | + TransItem::GlobalAsm(node_id) => Some(tcx.hir.local_def_id(node_id)), } } diff --git a/src/librustc_trans/symbol_map.rs b/src/librustc_trans/symbol_map.rs index 1b48e131b720a..36c3981e3a6f2 100644 --- a/src/librustc_trans/symbol_map.rs +++ b/src/librustc_trans/symbol_map.rs @@ -99,7 +99,10 @@ impl<'tcx> SymbolMap<'tcx> { TransItem::Fn(Instance { def, .. }) => { tcx.hir.as_local_node_id(def.def_id()) } - TransItem::Static(node_id) => Some(node_id), + TransItem::Static(node_id) | + TransItem::GlobalAsm(node_id) => { + Some(node_id) + } }.map(|node_id| { tcx.hir.span(node_id) }) diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs index 410e3f30be731..f5556bb8382f6 100644 --- a/src/librustc_trans/trans_item.rs +++ b/src/librustc_trans/trans_item.rs @@ -14,6 +14,7 @@ //! item-path. This is used for unit testing the code that generates //! paths etc in all kinds of annoying scenarios. +use asm; use attributes; use base; use consts; @@ -38,7 +39,8 @@ use std::iter; #[derive(PartialEq, Eq, Clone, Copy, Debug, Hash)] pub enum TransItem<'tcx> { Fn(Instance<'tcx>), - Static(NodeId) + Static(NodeId), + GlobalAsm(NodeId), } /// Describes how a translation item will be instantiated in object files. @@ -89,6 +91,14 @@ impl<'a, 'tcx> TransItem<'tcx> { span_bug!(item.span, "Mismatch between hir::Item type and TransItem type") } } + TransItem::GlobalAsm(node_id) => { + let item = ccx.tcx().hir.expect_item(node_id); + if let hir::ItemGlobalAsm(ref ga) = item.node { + asm::trans_global_asm(ccx, ga); + } else { + span_bug!(item.span, "Mismatch between hir::Item type and TransItem type") + } + } TransItem::Fn(instance) => { let _task = ccx.tcx().dep_graph.in_task( DepNode::TransCrateItem(instance.def_id())); // (*) @@ -123,6 +133,7 @@ impl<'a, 'tcx> TransItem<'tcx> { TransItem::Fn(instance) => { TransItem::predefine_fn(ccx, instance, linkage, &symbol_name); } + TransItem::GlobalAsm(..) => {} } debug!("END PREDEFINING '{} ({})' in cgu {}", @@ -185,6 +196,10 @@ impl<'a, 'tcx> TransItem<'tcx> { let def_id = scx.tcx().hir.local_def_id(node_id); symbol_names::symbol_name(Instance::mono(scx.tcx(), def_id), scx) } + TransItem::GlobalAsm(node_id) => { + let def_id = scx.tcx().hir.local_def_id(node_id); + format!("global_asm_{:?}", def_id) + } } } @@ -202,6 +217,7 @@ impl<'a, 'tcx> TransItem<'tcx> { } } TransItem::Static(..) => InstantiationMode::GloballyShared, + TransItem::GlobalAsm(..) => InstantiationMode::GloballyShared, } } @@ -210,7 +226,8 @@ impl<'a, 'tcx> TransItem<'tcx> { TransItem::Fn(ref instance) => { instance.substs.types().next().is_some() } - TransItem::Static(..) => false, + TransItem::Static(..) | + TransItem::GlobalAsm(..) => false, } } @@ -218,6 +235,7 @@ impl<'a, 'tcx> TransItem<'tcx> { let def_id = match *self { TransItem::Fn(ref instance) => instance.def_id(), TransItem::Static(node_id) => tcx.hir.local_def_id(node_id), + TransItem::GlobalAsm(..) => return None, }; let attributes = tcx.get_attrs(def_id); @@ -249,6 +267,9 @@ impl<'a, 'tcx> TransItem<'tcx> { let instance = Instance::new(def_id, tcx.intern_substs(&[])); to_string_internal(tcx, "static ", instance) }, + TransItem::GlobalAsm(..) => { + "global_asm".to_string() + } }; fn to_string_internal<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, @@ -273,6 +294,9 @@ impl<'a, 'tcx> TransItem<'tcx> { TransItem::Static(id) => { format!("Static({:?})", id) } + TransItem::GlobalAsm(id) => { + format!("GlobalAsm({:?})", id) + } } } } diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 1ed42b842c6fa..1b5d1ee945307 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -490,8 +490,10 @@ fn convert_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, item_id: ast::NodeId) { let def_id = tcx.hir.local_def_id(item_id); match it.node { // These don't define types. - hir::ItemExternCrate(_) | hir::ItemUse(..) | hir::ItemMod(_) => { - } + hir::ItemExternCrate(_) | + hir::ItemUse(..) | + hir::ItemMod(_) | + hir::ItemGlobalAsm(_) => {} hir::ItemForeignMod(ref foreign_mod) => { for item in &foreign_mod.items { let def_id = tcx.hir.local_def_id(item.id); @@ -543,12 +545,12 @@ fn convert_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, item_id: ast::NodeId) { tcx.item_generics(def_id); tcx.item_type(def_id); tcx.item_predicates(def_id); - }, - _ => { + } + hir::ItemStatic(..) | hir::ItemConst(..) | hir::ItemFn(..) => { tcx.item_generics(def_id); tcx.item_type(def_id); tcx.item_predicates(def_id); - }, + } } } @@ -1074,6 +1076,7 @@ fn ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ItemTrait(..) | ItemMod(..) | ItemForeignMod(..) | + ItemGlobalAsm(..) | ItemExternCrate(..) | ItemUse(..) => { span_bug!( diff --git a/src/librustc_typeck/variance/constraints.rs b/src/librustc_typeck/variance/constraints.rs index f0f543fa6f23b..1bde1eea37c39 100644 --- a/src/librustc_typeck/variance/constraints.rs +++ b/src/librustc_typeck/variance/constraints.rs @@ -113,6 +113,7 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for ConstraintContext<'a, 'tcx> { hir::ItemFn(..) | hir::ItemMod(..) | hir::ItemForeignMod(..) | + hir::ItemGlobalAsm(..) | hir::ItemTy(..) | hir::ItemImpl(..) | hir::ItemDefaultImpl(..) => {} diff --git a/src/librustc_typeck/variance/terms.rs b/src/librustc_typeck/variance/terms.rs index 36352f50e4406..890414e317c62 100644 --- a/src/librustc_typeck/variance/terms.rs +++ b/src/librustc_typeck/variance/terms.rs @@ -251,6 +251,7 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for TermsContext<'a, 'tcx> { hir::ItemFn(..) | hir::ItemMod(..) | hir::ItemForeignMod(..) | + hir::ItemGlobalAsm(..) | hir::ItemTy(..) => {} } } diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index c89ec5bbe15bd..4252f2981ed61 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -373,6 +373,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { } // If we're inlining, skip private items. _ if self.inlining && item.vis != hir::Public => {} + hir::ItemGlobalAsm(..) => {} hir::ItemExternCrate(ref p) => { let cstore = &self.cx.sess().cstore; om.extern_crates.push(ExternCrate { diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 9eb86aa006d17..08ea278df0ecb 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -1583,6 +1583,15 @@ pub struct ForeignMod { pub items: Vec, } +/// Global inline assembly +/// +/// aka module-level assembly or file-scoped assembly +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)] +pub struct GlobalAsm { + pub asm: Symbol, + pub ctxt: SyntaxContext, +} + #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub struct EnumDef { pub variants: Vec, @@ -1810,6 +1819,8 @@ pub enum ItemKind { /// /// E.g. `extern {}` or `extern "C" {}` ForeignMod(ForeignMod), + /// Module-level inline assembly (from `global_asm!()`) + GlobalAsm(P), /// A type alias (`type` or `pub type`). /// /// E.g. `type Foo = Bar;` @@ -1862,6 +1873,7 @@ impl ItemKind { ItemKind::Fn(..) => "function", ItemKind::Mod(..) => "module", ItemKind::ForeignMod(..) => "foreign module", + ItemKind::GlobalAsm(..) => "global asm", ItemKind::Ty(..) => "type alias", ItemKind::Enum(..) => "enum", ItemKind::Struct(..) => "struct", diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 1b3352f73ade7..48bfc050223ab 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -1039,6 +1039,7 @@ impl<'feat> ExpansionConfig<'feat> { feature_tests! { fn enable_quotes = quote, fn enable_asm = asm, + fn enable_global_asm = global_asm, fn enable_log_syntax = log_syntax, fn enable_concat_idents = concat_idents, fn enable_trace_macros = trace_macros, diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 412803ddcd5a3..631fe0cc1d89e 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -339,6 +339,9 @@ declare_features! ( // See rust-lang/rfcs#1414. Allows code like `let x: &'static u32 = &42` to work. (active, rvalue_static_promotion, "1.15.1", Some(38865)), + + // Allows module-level inline assembly by way of global_asm!() + (active, global_asm, "1.17.0", Some(35119)), ); declare_features! ( @@ -971,6 +974,9 @@ pub const EXPLAIN_STMT_ATTR_SYNTAX: &'static str = pub const EXPLAIN_ASM: &'static str = "inline assembly is not stable enough for use and is subject to change"; +pub const EXPLAIN_GLOBAL_ASM: &'static str = + "`global_asm!` is not stable enough for use and is subject to change"; + pub const EXPLAIN_LOG_SYNTAX: &'static str = "`log_syntax!` is not stable enough for use and is subject to change"; diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 1a4e196ac5577..06b8e071b7975 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -140,6 +140,10 @@ pub trait Folder : Sized { noop_fold_foreign_mod(nm, self) } + fn fold_global_asm(&mut self, ga: P) -> P { + noop_fold_global_asm(ga, self) + } + fn fold_variant(&mut self, v: Variant) -> Variant { noop_fold_variant(v, self) } @@ -412,6 +416,11 @@ pub fn noop_fold_foreign_mod(ForeignMod {abi, items}: ForeignMod, } } +pub fn noop_fold_global_asm(ga: P, + _: &mut T) -> P { + ga +} + pub fn noop_fold_variant(v: Variant, fld: &mut T) -> Variant { Spanned { node: Variant_ { @@ -867,6 +876,7 @@ pub fn noop_fold_item_kind(i: ItemKind, folder: &mut T) -> ItemKind { } ItemKind::Mod(m) => ItemKind::Mod(folder.fold_mod(m)), ItemKind::ForeignMod(nm) => ItemKind::ForeignMod(folder.fold_foreign_mod(nm)), + ItemKind::GlobalAsm(ga) => ItemKind::GlobalAsm(folder.fold_global_asm(ga)), ItemKind::Ty(t, generics) => { ItemKind::Ty(folder.fold_ty(t), folder.fold_generics(generics)) } diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index f042a18d61036..3c6254c442e22 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1264,6 +1264,11 @@ impl<'a> State<'a> { self.print_foreign_mod(nmod, &item.attrs)?; self.bclose(item.span)?; } + ast::ItemKind::GlobalAsm(ref ga) => { + self.head(&visibility_qualified(&item.vis, "global_asm!"))?; + word(&mut self.s, &ga.asm.as_str())?; + self.end()?; + } ast::ItemKind::Ty(ref ty, ref params) => { self.ibox(INDENT_UNIT)?; self.ibox(0)?; diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index a5333f3bb6a6e..36ed29f911cd1 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -58,6 +58,7 @@ pub trait Visitor<'ast>: Sized { } fn visit_mod(&mut self, m: &'ast Mod, _s: Span, _n: NodeId) { walk_mod(self, m) } fn visit_foreign_item(&mut self, i: &'ast ForeignItem) { walk_foreign_item(self, i) } + fn visit_global_asm(&mut self, ga: &'ast GlobalAsm) { walk_global_asm(self, ga) } fn visit_item(&mut self, i: &'ast Item) { walk_item(self, i) } fn visit_local(&mut self, l: &'ast Local) { walk_local(self, l) } fn visit_block(&mut self, b: &'ast Block) { walk_block(self, b) } @@ -253,6 +254,7 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) { ItemKind::ForeignMod(ref foreign_module) => { walk_list!(visitor, visit_foreign_item, &foreign_module.items); } + ItemKind::GlobalAsm(ref ga) => visitor.visit_global_asm(ga), ItemKind::Ty(ref typ, ref type_parameters) => { visitor.visit_ty(typ); visitor.visit_generics(type_parameters) @@ -464,6 +466,10 @@ pub fn walk_foreign_item<'a, V: Visitor<'a>>(visitor: &mut V, foreign_item: &'a walk_list!(visitor, visit_attribute, &foreign_item.attrs); } +pub fn walk_global_asm<'a, V: Visitor<'a>>(_: &mut V, _: &'a GlobalAsm) { + // Empty! +} + pub fn walk_ty_param_bound<'a, V: Visitor<'a>>(visitor: &mut V, bound: &'a TyParamBound) { match *bound { TraitTyParamBound(ref typ, ref modifier) => { diff --git a/src/libsyntax_ext/global_asm.rs b/src/libsyntax_ext/global_asm.rs new file mode 100644 index 0000000000000..dc67e1c45f6e7 --- /dev/null +++ b/src/libsyntax_ext/global_asm.rs @@ -0,0 +1,65 @@ +// Copyright 2012-2013 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +/// Module-level assembly support. +/// +/// The macro defined here allows you to specify "top-level", +/// "file-scoped", or "module-level" assembly. These synonyms +/// all correspond to LLVM's module-level inline assembly instruction. +/// +/// For example, `global_asm!("some assembly here")` translates to +/// LLVM's `module asm "some assembly here"`. All of LLVM's caveats +/// therefore apply. + +use syntax::ast; +use syntax::ext::base; +use syntax::ext::base::*; +use syntax::feature_gate; +use syntax::ptr::P; +use syntax::symbol::Symbol; +use syntax_pos::Span; +use syntax::tokenstream; + +use syntax::util::small_vector::SmallVector; + +pub const MACRO: &'static str = "global_asm"; + +pub fn expand_global_asm<'cx>(cx: &'cx mut ExtCtxt, + sp: Span, + tts: &[tokenstream::TokenTree]) -> Box { + if !cx.ecfg.enable_global_asm() { + feature_gate::emit_feature_err(&cx.parse_sess, + MACRO, + sp, + feature_gate::GateIssue::Language, + feature_gate::EXPLAIN_GLOBAL_ASM); + return DummyResult::any(sp); + } + + let mut p = cx.new_parser_from_tts(tts); + let (asm, _) = match expr_to_string(cx, + panictry!(p.parse_expr()), + "inline assembly must be a string literal") { + Some((s, st)) => (s, st), + None => return DummyResult::any(sp), + }; + + MacEager::items(SmallVector::one(P(ast::Item { + ident: ast::Ident::with_empty_ctxt(Symbol::intern("")), + attrs: Vec::new(), + id: ast::DUMMY_NODE_ID, + node: ast::ItemKind::GlobalAsm(P(ast::GlobalAsm { + asm: asm, + ctxt: cx.backtrace(), + })), + vis: ast::Visibility::Inherited, + span: sp, + }))) +} diff --git a/src/libsyntax_ext/lib.rs b/src/libsyntax_ext/lib.rs index 1e9b112b6df56..e35e79df58520 100644 --- a/src/libsyntax_ext/lib.rs +++ b/src/libsyntax_ext/lib.rs @@ -38,6 +38,7 @@ mod concat_idents; mod env; mod format; mod format_foreign; +mod global_asm; mod log_syntax; mod trace_macros; @@ -99,6 +100,7 @@ pub fn register_builtins(resolver: &mut syntax::ext::base::Resolver, module_path: expand_mod, asm: asm::expand_asm, + global_asm: global_asm::expand_global_asm, cfg: cfg::expand_cfg, concat: concat::expand_syntax_ext, concat_idents: concat_idents::expand_syntax_ext, diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp index 5ab786f40b933..c24867224ea86 100644 --- a/src/rustllvm/RustWrapper.cpp +++ b/src/rustllvm/RustWrapper.cpp @@ -312,6 +312,10 @@ extern "C" LLVMValueRef LLVMRustInlineAsm(LLVMTypeRef Ty, char *AsmString, HasSideEffects, IsAlignStack, fromRust(Dialect))); } +extern "C" void LLVMRustAppendModuleInlineAsm(LLVMModuleRef M, const char *Asm) { + unwrap(M)->appendModuleInlineAsm(StringRef(Asm)); +} + typedef DIBuilder *LLVMRustDIBuilderRef; typedef struct LLVMOpaqueMetadata *LLVMRustMetadataRef; diff --git a/src/test/codegen/foo.s b/src/test/codegen/foo.s new file mode 100644 index 0000000000000..304d82aa0c653 --- /dev/null +++ b/src/test/codegen/foo.s @@ -0,0 +1,3 @@ +.global foo +foo: + jmp baz diff --git a/src/test/codegen/global_asm.rs b/src/test/codegen/global_asm.rs new file mode 100644 index 0000000000000..5bd0c1b4076ee --- /dev/null +++ b/src/test/codegen/global_asm.rs @@ -0,0 +1,73 @@ +// Copyright 2017 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// ignore-aarch64 +// ignore-aarch64_be +// ignore-arm +// ignore-armeb +// ignore-avr +// ignore-bpfel +// ignore-bpfeb +// ignore-hexagon +// ignore-mips +// ignore-mipsel +// ignore-mips64 +// ignore-mips64el +// ignore-msp430 +// ignore-powerpc64 +// ignore-powerpc64le +// ignore-powerpc +// ignore-r600 +// ignore-amdgcn +// ignore-sparc +// ignore-sparcv9 +// ignore-sparcel +// ignore-s390x +// ignore-tce +// ignore-thumb +// ignore-thumbeb +// ignore-xcore +// ignore-nvptx +// ignore-nvptx64 +// ignore-le32 +// ignore-le64 +// ignore-amdil +// ignore-amdil64 +// ignore-hsail +// ignore-hsail64 +// ignore-spir +// ignore-spir64 +// ignore-kalimba +// ignore-shave +// ignore-wasm32 +// ignore-wasm64 +// ignore-emscripten +// compile-flags: -C no-prepopulate-passes + +#![feature(global_asm)] +#![crate_type = "lib"] + +// CHECK-LABEL: foo +// CHECK: module asm +// this regex will capture the correct unconditional branch inst. +// CHECK: module asm "{{[[:space:]]+}}jmp baz" +global_asm!(r#" + .global foo +foo: + jmp baz +"#); + +extern "C" { + fn foo(); +} + +// CHECK-LABEL: @baz +#[no_mangle] +pub unsafe extern "C" fn baz() {} diff --git a/src/test/codegen/global_asm_include.rs b/src/test/codegen/global_asm_include.rs new file mode 100644 index 0000000000000..401b1fad566d5 --- /dev/null +++ b/src/test/codegen/global_asm_include.rs @@ -0,0 +1,68 @@ +// Copyright 2017 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// ignore-aarch64 +// ignore-aarch64_be +// ignore-arm +// ignore-armeb +// ignore-avr +// ignore-bpfel +// ignore-bpfeb +// ignore-hexagon +// ignore-mips +// ignore-mipsel +// ignore-mips64 +// ignore-mips64el +// ignore-msp430 +// ignore-powerpc64 +// ignore-powerpc64le +// ignore-powerpc +// ignore-r600 +// ignore-amdgcn +// ignore-sparc +// ignore-sparcv9 +// ignore-sparcel +// ignore-s390x +// ignore-tce +// ignore-thumb +// ignore-thumbeb +// ignore-xcore +// ignore-nvptx +// ignore-nvptx64 +// ignore-le32 +// ignore-le64 +// ignore-amdil +// ignore-amdil64 +// ignore-hsail +// ignore-hsail64 +// ignore-spir +// ignore-spir64 +// ignore-kalimba +// ignore-shave +// ignore-wasm32 +// ignore-wasm64 +// ignore-emscripten +// compile-flags: -C no-prepopulate-passes + +#![feature(global_asm)] +#![crate_type = "lib"] + +// CHECK-LABEL: foo +// CHECK: module asm +// CHECK: module asm "{{[[:space:]]+}}jmp baz" +global_asm!(include_str!("foo.s")); + +extern "C" { + fn foo(); +} + +// CHECK-LABEL: @baz +#[no_mangle] +pub unsafe extern "C" fn baz() {} diff --git a/src/test/codegen/global_asm_x2.rs b/src/test/codegen/global_asm_x2.rs new file mode 100644 index 0000000000000..8b59165e9e61b --- /dev/null +++ b/src/test/codegen/global_asm_x2.rs @@ -0,0 +1,90 @@ +// Copyright 2017 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// ignore-aarch64 +// ignore-aarch64_be +// ignore-arm +// ignore-armeb +// ignore-avr +// ignore-bpfel +// ignore-bpfeb +// ignore-hexagon +// ignore-mips +// ignore-mipsel +// ignore-mips64 +// ignore-mips64el +// ignore-msp430 +// ignore-powerpc64 +// ignore-powerpc64le +// ignore-powerpc +// ignore-r600 +// ignore-amdgcn +// ignore-sparc +// ignore-sparcv9 +// ignore-sparcel +// ignore-s390x +// ignore-tce +// ignore-thumb +// ignore-thumbeb +// ignore-xcore +// ignore-nvptx +// ignore-nvptx64 +// ignore-le32 +// ignore-le64 +// ignore-amdil +// ignore-amdil64 +// ignore-hsail +// ignore-hsail64 +// ignore-spir +// ignore-spir64 +// ignore-kalimba +// ignore-shave +// ignore-wasm32 +// ignore-wasm64 +// ignore-emscripten +// compile-flags: -C no-prepopulate-passes + +#![feature(global_asm)] +#![crate_type = "lib"] +#[no_std] + +// CHECK-LABEL: foo +// CHECK: module asm +// CHECK: module asm "{{[[:space:]]+}}jmp baz" +// any other global_asm will be appended to this first block, so: +// CHECK-LABEL: bar +// CHECK: module asm "{{[[:space:]]+}}jmp quux" +global_asm!(r#" + .global foo +foo: + jmp baz +"#); + +extern "C" { + fn foo(); +} + +// CHECK-LABEL: @baz +#[no_mangle] +pub unsafe extern "C" fn baz() {} + +// no checks here; this has been appended to the first occurrence +global_asm!(r#" + .global bar +bar: + jmp quux +"#); + +extern "C" { + fn bar(); +} + +#[no_mangle] +pub unsafe extern "C" fn quux() {} diff --git a/src/test/compile-fail/feature-gate-global_asm.rs b/src/test/compile-fail/feature-gate-global_asm.rs new file mode 100644 index 0000000000000..0560abb6af498 --- /dev/null +++ b/src/test/compile-fail/feature-gate-global_asm.rs @@ -0,0 +1,15 @@ +// Copyright 2014 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// gate-test-global_asm + +global_asm!(""); //~ ERROR `global_asm!` is not stable + +fn main() {} diff --git a/src/test/run-pass/empty_global_asm.rs b/src/test/run-pass/empty_global_asm.rs new file mode 100644 index 0000000000000..db73da2747f9c --- /dev/null +++ b/src/test/run-pass/empty_global_asm.rs @@ -0,0 +1,28 @@ +// Copyright 2017 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(global_asm)] + +#[cfg(target_arch = "x86")] +global_asm!(""); + +#[cfg(target_arch = "x86_64")] +global_asm!(""); + +#[cfg(target_arch = "arm")] +global_asm!(""); + +#[cfg(target_arch = "aarch64")] +global_asm!(""); + +#[cfg(target_arch = "mips")] +global_asm!(""); + +fn main() {} diff --git a/src/test/run-pass/simple_global_asm.rs b/src/test/run-pass/simple_global_asm.rs new file mode 100644 index 0000000000000..a5ffe607fdf84 --- /dev/null +++ b/src/test/run-pass/simple_global_asm.rs @@ -0,0 +1,27 @@ +// Copyright 2017 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(global_asm)] + +#[cfg(any(target_arch = "x86_64", target_arch = "x86"))] +global_asm!(r#" + .global foo +foo: + jmp baz +"#); + +extern { + fn foo(); +} + +#[no_mangle] +pub extern fn baz() {} + +fn main() {}