mirror of
https://github.com/EmbarkStudios/rust-gpu.git
synced 2024-11-24 07:45:05 +00:00
asm! (#254)
This commit is contained in:
parent
c1c72517c8
commit
bedbc4dc0f
6
Cargo.lock
generated
6
Cargo.lock
generated
@ -1952,12 +1952,12 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "rspirv"
|
||||
version = "0.7.0"
|
||||
source = "git+https://github.com/gfx-rs/rspirv.git?rev=f11f8797bd4df2d1d22cf10767b39a5119c57551#f11f8797bd4df2d1d22cf10767b39a5119c57551"
|
||||
source = "git+https://github.com/gfx-rs/rspirv.git?rev=01ca0d2e5b667a0e4ff1bc1804511e38f9a08759#01ca0d2e5b667a0e4ff1bc1804511e38f9a08759"
|
||||
dependencies = [
|
||||
"derive_more",
|
||||
"fxhash",
|
||||
"num-traits",
|
||||
"spirv_headers 1.5.0 (git+https://github.com/gfx-rs/rspirv.git?rev=f11f8797bd4df2d1d22cf10767b39a5119c57551)",
|
||||
"spirv_headers 1.5.0 (git+https://github.com/gfx-rs/rspirv.git?rev=01ca0d2e5b667a0e4ff1bc1804511e38f9a08759)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -2210,7 +2210,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "spirv_headers"
|
||||
version = "1.5.0"
|
||||
source = "git+https://github.com/gfx-rs/rspirv.git?rev=f11f8797bd4df2d1d22cf10767b39a5119c57551#f11f8797bd4df2d1d22cf10767b39a5119c57551"
|
||||
source = "git+https://github.com/gfx-rs/rspirv.git?rev=01ca0d2e5b667a0e4ff1bc1804511e38f9a08759#01ca0d2e5b667a0e4ff1bc1804511e38f9a08759"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"num-traits",
|
||||
|
@ -28,7 +28,7 @@ use-compiled-tools = ["spirv-tools/use-compiled-tools"]
|
||||
|
||||
[dependencies]
|
||||
bimap = "0.5"
|
||||
rspirv = { git = "https://github.com/gfx-rs/rspirv.git", rev = "f11f8797bd4df2d1d22cf10767b39a5119c57551" }
|
||||
rspirv = { git = "https://github.com/gfx-rs/rspirv.git", rev = "01ca0d2e5b667a0e4ff1bc1804511e38f9a08759" }
|
||||
spirv-tools = { version = "0.1.0", default-features = false }
|
||||
tar = "0.4.30"
|
||||
topological-sort = "0.1"
|
||||
|
@ -1,24 +1,23 @@
|
||||
mod builder_methods;
|
||||
mod ext_inst;
|
||||
mod intrinsics;
|
||||
mod spirv_asm;
|
||||
|
||||
pub use ext_inst::ExtInst;
|
||||
pub use spirv_asm::InstructionTable;
|
||||
|
||||
use crate::abi::ConvSpirvType;
|
||||
use crate::builder_spirv::{BuilderCursor, SpirvValue, SpirvValueExt};
|
||||
use crate::codegen_cx::CodegenCx;
|
||||
use crate::spirv_type::SpirvType;
|
||||
use rspirv::spirv::{StorageClass, Word};
|
||||
use rustc_ast::ast::{InlineAsmOptions, InlineAsmTemplatePiece};
|
||||
use rustc_codegen_ssa::mir::operand::OperandValue;
|
||||
use rustc_codegen_ssa::mir::place::PlaceRef;
|
||||
use rustc_codegen_ssa::traits::{
|
||||
AbiBuilderMethods, ArgAbiMethods, AsmBuilderMethods, BackendTypes, BuilderMethods,
|
||||
CoverageInfoBuilderMethods, DebugInfoBuilderMethods, HasCodegen, InlineAsmOperandRef,
|
||||
StaticBuilderMethods,
|
||||
AbiBuilderMethods, ArgAbiMethods, BackendTypes, BuilderMethods, CoverageInfoBuilderMethods,
|
||||
DebugInfoBuilderMethods, HasCodegen, StaticBuilderMethods,
|
||||
};
|
||||
use rustc_errors::DiagnosticBuilder;
|
||||
use rustc_hir::LlvmInlineAsmInner;
|
||||
use rustc_middle::mir::coverage::{
|
||||
CodeRegion, CounterValueReference, ExpressionOperandId, InjectedExpressionId, Op,
|
||||
};
|
||||
@ -343,28 +342,6 @@ impl<'a, 'tcx> AbiBuilderMethods<'tcx> for Builder<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'tcx> {
|
||||
fn codegen_llvm_inline_asm(
|
||||
&mut self,
|
||||
_ia: &LlvmInlineAsmInner,
|
||||
_outputs: Vec<PlaceRef<'tcx, Self::Value>>,
|
||||
_inputs: Vec<Self::Value>,
|
||||
_span: Span,
|
||||
) -> bool {
|
||||
self.err("LLVM asm not supported");
|
||||
true
|
||||
}
|
||||
|
||||
fn codegen_inline_asm(
|
||||
&mut self,
|
||||
_template: &[InlineAsmTemplatePiece],
|
||||
_operands: &[InlineAsmOperandRef<'tcx, Self>],
|
||||
_options: InlineAsmOptions,
|
||||
_line_spans: &[Span],
|
||||
) {
|
||||
self.err("asm not supported")
|
||||
}
|
||||
}
|
||||
impl<'a, 'tcx> StaticBuilderMethods for Builder<'a, 'tcx> {
|
||||
fn get_static(&mut self, def_id: DefId) -> Self::Value {
|
||||
self.cx.get_static(def_id)
|
||||
|
1025
crates/rustc_codegen_spirv/src/builder/spirv_asm.rs
Normal file
1025
crates/rustc_codegen_spirv/src/builder/spirv_asm.rs
Normal file
File diff suppressed because it is too large
Load Diff
@ -10,7 +10,7 @@ use rustc_middle::bug;
|
||||
use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
|
||||
use rustc_middle::mir::mono::{Linkage, MonoItem, Visibility};
|
||||
use rustc_middle::ty::layout::FnAbiExt;
|
||||
use rustc_middle::ty::{Instance, ParamEnv, Ty, TypeFoldable};
|
||||
use rustc_middle::ty::{Instance, ParamEnv, TypeFoldable};
|
||||
use rustc_span::def_id::DefId;
|
||||
use rustc_span::Span;
|
||||
use rustc_target::abi::call::FnAbi;
|
||||
@ -43,14 +43,10 @@ impl<'tcx> CodegenCx<'tcx> {
|
||||
return func;
|
||||
}
|
||||
|
||||
let sym = self.tcx.symbol_name(instance).name;
|
||||
// Because we've already declared everything with predefine_fn, if we hit this branch, we're guaranteed to be
|
||||
// importing this function from elsewhere. So, slap an extern on it.
|
||||
let human_name = format!("{}", instance);
|
||||
let linkage = Some(LinkageType::Import);
|
||||
let attrs = attrs_to_spirv(self.tcx.codegen_fn_attrs(instance.def_id()));
|
||||
let fn_abi = FnAbi::of_instance(self, instance, &[]);
|
||||
let llfn = self.declare_fn_ext(sym, Some(&human_name), linkage, attrs, &fn_abi);
|
||||
let llfn = self.declare_fn_ext(instance, linkage);
|
||||
|
||||
self.instances.borrow_mut().insert(instance, llfn);
|
||||
|
||||
@ -61,14 +57,10 @@ impl<'tcx> CodegenCx<'tcx> {
|
||||
// MiscMethods::get_fn -> get_fn_ext -> declare_fn_ext
|
||||
// MiscMethods::get_fn_addr -> get_fn_ext -> declare_fn_ext
|
||||
// PreDefineMethods::predefine_fn -> declare_fn_ext
|
||||
fn declare_fn_ext(
|
||||
&self,
|
||||
name: &str,
|
||||
human_name: Option<&str>,
|
||||
linkage: Option<LinkageType>,
|
||||
control: FunctionControl,
|
||||
fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
|
||||
) -> SpirvValue {
|
||||
fn declare_fn_ext(&self, instance: Instance<'tcx>, linkage: Option<LinkageType>) -> SpirvValue {
|
||||
let symbol_name = self.tcx.symbol_name(instance).name;
|
||||
let control = attrs_to_spirv(self.tcx.codegen_fn_attrs(instance.def_id()));
|
||||
let fn_abi = FnAbi::of_instance(self, instance, &[]);
|
||||
let function_type = fn_abi.spirv_type(self);
|
||||
let (return_type, argument_types) = match self.lookup_type(function_type) {
|
||||
SpirvType::Function {
|
||||
@ -78,7 +70,7 @@ impl<'tcx> CodegenCx<'tcx> {
|
||||
other => bug!("fn_abi type {}", other.debug(function_type, self)),
|
||||
};
|
||||
|
||||
if crate::is_blocklisted_fn(name) {
|
||||
if crate::is_blocklisted_fn(symbol_name) {
|
||||
// This can happen if we call a blocklisted function in another crate.
|
||||
let result = self.undef(function_type);
|
||||
// TODO: Span info here
|
||||
@ -99,16 +91,31 @@ impl<'tcx> CodegenCx<'tcx> {
|
||||
.insert(fn_id, parameter_values);
|
||||
}
|
||||
emit.end_function().unwrap();
|
||||
match human_name {
|
||||
Some(human_name) => emit.name(fn_id, human_name),
|
||||
None => emit.name(fn_id, name),
|
||||
}
|
||||
|
||||
let human_name = format!("{}", instance);
|
||||
emit.name(fn_id, &human_name);
|
||||
drop(emit); // set_linkage uses emit
|
||||
if let Some(linkage) = linkage {
|
||||
self.set_linkage(fn_id, name.to_owned(), linkage);
|
||||
self.set_linkage(fn_id, symbol_name.to_owned(), linkage);
|
||||
}
|
||||
|
||||
fn_id.with_type(function_type)
|
||||
let declared = fn_id.with_type(function_type);
|
||||
|
||||
for attr in parse_attrs(self, self.tcx.get_attrs(instance.def_id())) {
|
||||
match attr {
|
||||
SpirvAttribute::Entry(entry) => {
|
||||
self.entry_stub(&instance, &fn_abi, declared, human_name.clone(), entry)
|
||||
}
|
||||
SpirvAttribute::ReallyUnsafeIgnoreBitcasts => {
|
||||
self.really_unsafe_ignore_bitcasts
|
||||
.borrow_mut()
|
||||
.insert(declared);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
declared
|
||||
}
|
||||
|
||||
pub fn get_static(&self, def_id: DefId) -> SpirvValue {
|
||||
@ -175,11 +182,6 @@ impl<'tcx> PreDefineMethods<'tcx> for CodegenCx<'tcx> {
|
||||
let span = self.tcx.def_span(def_id);
|
||||
let g = self.declare_global(span, spvty);
|
||||
|
||||
// unsafe {
|
||||
// llvm::LLVMRustSetLinkage(g, base::linkage_to_llvm(linkage));
|
||||
// llvm::LLVMRustSetVisibility(g, base::visibility_to_llvm(visibility));
|
||||
// }
|
||||
|
||||
self.instances.borrow_mut().insert(instance, g);
|
||||
if let Some(linkage) = linkage {
|
||||
self.set_linkage(g.def_cx(self), symbol_name.to_string(), linkage);
|
||||
@ -191,10 +193,8 @@ impl<'tcx> PreDefineMethods<'tcx> for CodegenCx<'tcx> {
|
||||
instance: Instance<'tcx>,
|
||||
linkage: Linkage,
|
||||
_visibility: Visibility,
|
||||
symbol_name: &str,
|
||||
_symbol_name: &str,
|
||||
) {
|
||||
let fn_abi = FnAbi::of_instance(self, instance, &[]);
|
||||
let human_name = format!("{}", instance);
|
||||
let linkage2 = match linkage {
|
||||
Linkage::External => Some(LinkageType::Export),
|
||||
Linkage::Internal => None,
|
||||
@ -203,25 +203,7 @@ impl<'tcx> PreDefineMethods<'tcx> for CodegenCx<'tcx> {
|
||||
other
|
||||
)),
|
||||
};
|
||||
let rust_attrs = self.tcx.codegen_fn_attrs(instance.def_id());
|
||||
let spv_attrs = attrs_to_spirv(rust_attrs);
|
||||
|
||||
let declared =
|
||||
self.declare_fn_ext(symbol_name, Some(&human_name), linkage2, spv_attrs, &fn_abi);
|
||||
|
||||
for attr in parse_attrs(self, self.tcx.get_attrs(instance.def_id())) {
|
||||
match attr {
|
||||
SpirvAttribute::Entry(entry) => {
|
||||
self.entry_stub(&instance, &fn_abi, declared, human_name.clone(), entry)
|
||||
}
|
||||
SpirvAttribute::ReallyUnsafeIgnoreBitcasts => {
|
||||
self.really_unsafe_ignore_bitcasts
|
||||
.borrow_mut()
|
||||
.insert(declared);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
let declared = self.declare_fn_ext(instance, linkage2);
|
||||
|
||||
self.instances.borrow_mut().insert(instance, declared);
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ mod declare;
|
||||
mod entry;
|
||||
mod type_;
|
||||
|
||||
use crate::builder::ExtInst;
|
||||
use crate::builder::{ExtInst, InstructionTable};
|
||||
use crate::builder_spirv::{BuilderCursor, BuilderSpirv, SpirvValue, SpirvValueKind};
|
||||
use crate::finalizing_passes::export_zombies;
|
||||
use crate::spirv_type::{SpirvType, SpirvTypePrinter, TypeCache};
|
||||
@ -50,6 +50,7 @@ pub struct CodegenCx<'tcx> {
|
||||
pub kernel_mode: bool,
|
||||
/// Cache of all the builtin symbols we need
|
||||
pub sym: Box<Symbols>,
|
||||
pub instruction_table: InstructionTable,
|
||||
pub really_unsafe_ignore_bitcasts: RefCell<HashSet<SpirvValue>>,
|
||||
pub zombie_undefs_for_system_constant_pointers: RefCell<HashMap<Word, Word>>,
|
||||
/// Some runtimes (e.g. intel-compute-runtime) disallow atomics on i8 and i16, even though it's allowed by the spec.
|
||||
@ -100,6 +101,7 @@ impl<'tcx> CodegenCx<'tcx> {
|
||||
zombie_values: Default::default(),
|
||||
kernel_mode,
|
||||
sym,
|
||||
instruction_table: InstructionTable::new(),
|
||||
really_unsafe_ignore_bitcasts: Default::default(),
|
||||
zombie_undefs_for_system_constant_pointers: Default::default(),
|
||||
i8_i16_atomics_allowed: false,
|
||||
@ -263,7 +265,7 @@ impl<'tcx> MiscMethods<'tcx> for CodegenCx<'tcx> {
|
||||
}
|
||||
|
||||
fn get_fn_addr(&self, instance: Instance<'tcx>) -> Self::Value {
|
||||
let function = self.get_fn_ext(instance);
|
||||
let function = self.get_fn(instance);
|
||||
self.make_constant_pointer(function)
|
||||
}
|
||||
|
||||
|
@ -34,6 +34,69 @@ OpFunctionEnd"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn asm() {
|
||||
dis_fn(
|
||||
r#"
|
||||
fn asm() {
|
||||
unsafe {
|
||||
asm!(
|
||||
"%int = OpTypeInt 32 0",
|
||||
"%scope = OpConstant %int 2",
|
||||
"%semantics = OpConstant %int 8452",
|
||||
"OpMemoryBarrier %scope %semantics",
|
||||
);
|
||||
}
|
||||
}
|
||||
#[allow(unused_attributes)]
|
||||
#[spirv(fragment)]
|
||||
pub fn main() {
|
||||
asm();
|
||||
}
|
||||
"#,
|
||||
"asm",
|
||||
// note: the OpConstants get hoisted out to global in the linker merge pass
|
||||
r#"%1 = OpFunction %2 None %3
|
||||
%4 = OpLabel
|
||||
OpMemoryBarrier %5 %6
|
||||
OpReturn
|
||||
OpFunctionEnd"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn asm_add_two_ints() {
|
||||
dis_fn(
|
||||
r#"
|
||||
fn add_two_ints(x: u32, y: u32) -> u32 {
|
||||
let result;
|
||||
unsafe {
|
||||
asm!(
|
||||
"{0} = OpIAdd typeof{0} {1} {2}",
|
||||
out(reg) result,
|
||||
in(reg) x,
|
||||
in(reg) y,
|
||||
);
|
||||
}
|
||||
result
|
||||
}
|
||||
#[allow(unused_attributes)]
|
||||
#[spirv(fragment)]
|
||||
pub fn main() {
|
||||
add_two_ints(2, 3);
|
||||
}
|
||||
"#,
|
||||
"add_two_ints",
|
||||
r#"%1 = OpFunction %2 None %3
|
||||
%4 = OpFunctionParameter %2
|
||||
%5 = OpFunctionParameter %2
|
||||
%6 = OpLabel
|
||||
%7 = OpIAdd %2 %4 %5
|
||||
OpReturnValue %7
|
||||
OpFunctionEnd"#,
|
||||
);
|
||||
}
|
||||
|
||||
// TODO: Implement strings to make this compile
|
||||
#[test]
|
||||
#[ignore]
|
||||
|
@ -49,7 +49,7 @@ spirv-std = { path = "../../crates/spirv-std" }
|
||||
"#;
|
||||
|
||||
static SRC_PREFIX: &str = r#"#![no_std]
|
||||
#![feature(lang_items, register_attr)]
|
||||
#![feature(lang_items, register_attr, asm)]
|
||||
#![register_attr(spirv)]
|
||||
use core::panic::PanicInfo;
|
||||
#[allow(unused_imports)]
|
||||
|
@ -1 +1 @@
|
||||
nightly-2020-11-13
|
||||
nightly-2020-11-15
|
||||
|
@ -1,6 +1,6 @@
|
||||
setlocal
|
||||
|
||||
rustup toolchain install nightly-2020-11-13 --component rust-src rustc-dev llvm-tools-preview
|
||||
rustup toolchain install nightly-2020-11-15 --component rust-src rustc-dev llvm-tools-preview
|
||||
|
||||
git submodule init
|
||||
git submodule update
|
||||
|
Loading…
Reference in New Issue
Block a user