From 94d270aee0b51b5b9ea8d6d26334ab3788a6dd92 Mon Sep 17 00:00:00 2001 From: msiglreith Date: Tue, 10 Aug 2021 19:20:23 +0200 Subject: [PATCH 1/5] asm: add support for noreturn option OpUnreachable will be appended as terminator at the end of the asm block. --- crates/rustc_codegen_spirv/src/builder/spirv_asm.rs | 9 +++++++-- crates/spirv-std/src/arch.rs | 5 +---- crates/spirv-std/src/arch/ray_tracing.rs | 10 ++++++---- crates/spirv-std/src/lib.rs | 2 +- crates/spirv-std/src/ray_tracing.rs | 4 ++-- crates/spirv-std/src/runtime_array.rs | 4 ++-- 6 files changed, 19 insertions(+), 15 deletions(-) diff --git a/crates/rustc_codegen_spirv/src/builder/spirv_asm.rs b/crates/rustc_codegen_spirv/src/builder/spirv_asm.rs index 57fe340ad5..9582212c39 100644 --- a/crates/rustc_codegen_spirv/src/builder/spirv_asm.rs +++ b/crates/rustc_codegen_spirv/src/builder/spirv_asm.rs @@ -70,8 +70,13 @@ impl<'a, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'tcx> { options: InlineAsmOptions, _line_spans: &[Span], ) { - if !options.is_empty() { - self.err(&format!("asm flags not supported: {:?}", options)); + const SUPPORTED_OPTIONS: InlineAsmOptions = InlineAsmOptions::NORETURN; + let unsupported_options = options & !SUPPORTED_OPTIONS; + if !unsupported_options.is_empty() { + self.err(&format!( + "asm flags not supported: {:?}", + unsupported_options + )); } // vec of lines, and each line is vec of tokens let mut tokens = vec![vec![]]; diff --git a/crates/spirv-std/src/arch.rs b/crates/spirv-std/src/arch.rs index 2e16c94cbf..91d2992347 100644 --- a/crates/spirv-std/src/arch.rs +++ b/crates/spirv-std/src/arch.rs @@ -148,8 +148,5 @@ pub unsafe fn vector_insert_dynamic, const N: usize>( #[doc(alias = "OpKill", alias = "discard")] #[allow(clippy::empty_loop)] pub fn kill() -> ! { - unsafe { - asm!("OpKill", "%unused = OpLabel"); - } - loop {} + unsafe { asm!("OpKill", "%unused = OpLabel", options(noreturn)) } } diff --git a/crates/spirv-std/src/arch/ray_tracing.rs b/crates/spirv-std/src/arch/ray_tracing.rs index d8b432dd4c..f766277898 100644 --- a/crates/spirv-std/src/arch/ray_tracing.rs +++ b/crates/spirv-std/src/arch/ray_tracing.rs @@ -44,8 +44,11 @@ pub unsafe fn report_intersection(hit: f32, hit_kind: u32) -> bool { #[inline] #[allow(clippy::empty_loop)] pub unsafe fn ignore_intersection() -> ! { - asm!("OpIgnoreIntersectionKHR", "%unused = OpLabel"); - loop {} + asm!( + "OpIgnoreIntersectionKHR", + "%unused = OpLabel", + options(noreturn) + ); } /// Terminates the invocation that executes it, stops the ray traversal, accepts @@ -57,8 +60,7 @@ pub unsafe fn ignore_intersection() -> ! { #[inline] #[allow(clippy::empty_loop)] pub unsafe fn terminate_ray() -> ! { - asm!("OpTerminateRayKHR", "%unused = OpLabel"); - loop {} + asm!("OpTerminateRayKHR", "%unused = OpLabel", options(noreturn)); } /// Invoke a callable shader. diff --git a/crates/spirv-std/src/lib.rs b/crates/spirv-std/src/lib.rs index 8c4c2080c6..f104456f82 100644 --- a/crates/spirv-std/src/lib.rs +++ b/crates/spirv-std/src/lib.rs @@ -118,7 +118,7 @@ pub use glam; #[cfg(all(not(test), target_arch = "spirv"))] #[panic_handler] fn panic(_: &core::panic::PanicInfo<'_>) -> ! { - loop {} + unsafe { asm!("", options(noreturn)) } } #[cfg(all(not(test), target_arch = "spirv"))] diff --git a/crates/spirv-std/src/ray_tracing.rs b/crates/spirv-std/src/ray_tracing.rs index a73993013b..6ca4f7b698 100644 --- a/crates/spirv-std/src/ray_tracing.rs +++ b/crates/spirv-std/src/ray_tracing.rs @@ -27,8 +27,8 @@ impl AccelerationStructure { "OpReturnValue %result", "%blah = OpLabel", id = in(reg) id, + options(noreturn) } - loop {} } /// Converts a vector of two 32 bit integers into an [`AccelerationStructure`]. @@ -49,8 +49,8 @@ impl AccelerationStructure { "OpReturnValue %result", "%blah = OpLabel", id = in(reg) &id, + options(noreturn), } - loop {} } #[spirv_std_macros::gpu_only] diff --git a/crates/spirv-std/src/runtime_array.rs b/crates/spirv-std/src/runtime_array.rs index d5bddbeb1a..011a4a978a 100644 --- a/crates/spirv-std/src/runtime_array.rs +++ b/crates/spirv-std/src/runtime_array.rs @@ -20,8 +20,8 @@ impl RuntimeArray { "%unused = OpLabel", arr = in(reg) self, index = in(reg) index, + options(noreturn), } - loop {} } #[spirv_std_macros::gpu_only] @@ -33,7 +33,7 @@ impl RuntimeArray { "%unused = OpLabel", arr = in(reg) self, index = in(reg) index, + options(noreturn), } - loop {} } } From def653a943bcd4308233bd79543a43c0ba2b3733 Mon Sep 17 00:00:00 2001 From: msiglreith Date: Tue, 10 Aug 2021 20:42:35 +0200 Subject: [PATCH 2/5] asm: implicit label after return or abort terminator --- .../src/builder/spirv_asm.rs | 18 ++++++++++++++++-- crates/spirv-std/src/arch.rs | 2 +- crates/spirv-std/src/arch/ray_tracing.rs | 8 ++------ crates/spirv-std/src/ray_tracing.rs | 2 -- crates/spirv-std/src/runtime_array.rs | 2 -- 5 files changed, 19 insertions(+), 13 deletions(-) diff --git a/crates/rustc_codegen_spirv/src/builder/spirv_asm.rs b/crates/rustc_codegen_spirv/src/builder/spirv_asm.rs index 9582212c39..d4b6bf4763 100644 --- a/crates/rustc_codegen_spirv/src/builder/spirv_asm.rs +++ b/crates/rustc_codegen_spirv/src/builder/spirv_asm.rs @@ -3,7 +3,7 @@ use crate::builder_spirv::{BuilderCursor, SpirvValue}; use crate::codegen_cx::CodegenCx; use crate::spirv_type::SpirvType; use rspirv::dr; -use rspirv::grammar::{LogicalOperand, OperandKind, OperandQuantifier}; +use rspirv::grammar::{reflect, LogicalOperand, OperandKind, OperandQuantifier}; use rspirv::spirv::{ FPFastMathMode, FragmentShadingRate, FunctionControl, ImageOperands, KernelProfilingInfo, LoopControl, MemoryAccess, MemorySemantics, Op, RayFlags, SelectionControl, StorageClass, Word, @@ -333,10 +333,24 @@ impl<'cx, 'tcx> Builder<'cx, 'tcx> { } return; } - _ => { + + op => { self.emit() .insert_into_block(dr::InsertPoint::End, inst) .unwrap(); + + // Return or abort terminators will also end the current block and start a new one. + // The new block is transparent to the actual builder cursor. + if reflect::is_return_or_abort(op) { + let label = self.emit().id(); + self.emit() + .insert_into_block( + dr::InsertPoint::End, + dr::Instruction::new(Op::Label, None, Some(label), vec![]), + ) + .unwrap(); + } + return; } }; diff --git a/crates/spirv-std/src/arch.rs b/crates/spirv-std/src/arch.rs index 91d2992347..00f0f28b84 100644 --- a/crates/spirv-std/src/arch.rs +++ b/crates/spirv-std/src/arch.rs @@ -148,5 +148,5 @@ pub unsafe fn vector_insert_dynamic, const N: usize>( #[doc(alias = "OpKill", alias = "discard")] #[allow(clippy::empty_loop)] pub fn kill() -> ! { - unsafe { asm!("OpKill", "%unused = OpLabel", options(noreturn)) } + unsafe { asm!("OpKill", options(noreturn)) } } diff --git a/crates/spirv-std/src/arch/ray_tracing.rs b/crates/spirv-std/src/arch/ray_tracing.rs index f766277898..b1933c1ab3 100644 --- a/crates/spirv-std/src/arch/ray_tracing.rs +++ b/crates/spirv-std/src/arch/ray_tracing.rs @@ -44,11 +44,7 @@ pub unsafe fn report_intersection(hit: f32, hit_kind: u32) -> bool { #[inline] #[allow(clippy::empty_loop)] pub unsafe fn ignore_intersection() -> ! { - asm!( - "OpIgnoreIntersectionKHR", - "%unused = OpLabel", - options(noreturn) - ); + asm!("OpIgnoreIntersectionKHR", options(noreturn)); } /// Terminates the invocation that executes it, stops the ray traversal, accepts @@ -60,7 +56,7 @@ pub unsafe fn ignore_intersection() -> ! { #[inline] #[allow(clippy::empty_loop)] pub unsafe fn terminate_ray() -> ! { - asm!("OpTerminateRayKHR", "%unused = OpLabel", options(noreturn)); + asm!("OpTerminateRayKHR", options(noreturn)); } /// Invoke a callable shader. diff --git a/crates/spirv-std/src/ray_tracing.rs b/crates/spirv-std/src/ray_tracing.rs index 6ca4f7b698..914290cdcc 100644 --- a/crates/spirv-std/src/ray_tracing.rs +++ b/crates/spirv-std/src/ray_tracing.rs @@ -25,7 +25,6 @@ impl AccelerationStructure { "%ret = OpTypeAccelerationStructureKHR", "%result = OpConvertUToAccelerationStructureKHR %ret {id}", "OpReturnValue %result", - "%blah = OpLabel", id = in(reg) id, options(noreturn) } @@ -47,7 +46,6 @@ impl AccelerationStructure { "%id = OpLoad _ {id}", "%result = OpConvertUToAccelerationStructureKHR %ret %id", "OpReturnValue %result", - "%blah = OpLabel", id = in(reg) &id, options(noreturn), } diff --git a/crates/spirv-std/src/runtime_array.rs b/crates/spirv-std/src/runtime_array.rs index 011a4a978a..12861f8de7 100644 --- a/crates/spirv-std/src/runtime_array.rs +++ b/crates/spirv-std/src/runtime_array.rs @@ -17,7 +17,6 @@ impl RuntimeArray { asm! { "%result = OpAccessChain _ {arr} {index}", "OpReturnValue %result", - "%unused = OpLabel", arr = in(reg) self, index = in(reg) index, options(noreturn), @@ -30,7 +29,6 @@ impl RuntimeArray { asm! { "%result = OpAccessChain _ {arr} {index}", "OpReturnValue %result", - "%unused = OpLabel", arr = in(reg) self, index = in(reg) index, options(noreturn), From 5a4e7d2252a336ac97d6ce19d34f40c0566ccf12 Mon Sep 17 00:00:00 2001 From: msiglreith Date: Thu, 12 Aug 2021 19:24:39 +0200 Subject: [PATCH 3/5] rework handling --- .../src/builder/spirv_asm.rs | 58 +++++++++++++++---- crates/spirv-std/src/lib.rs | 2 +- tests/ui/lang/asm/block_tracking_fail.rs | 41 +++++++++++++ tests/ui/lang/asm/block_tracking_fail.stderr | 29 ++++++++++ tests/ui/lang/asm/block_tracking_pass.rs | 28 +++++++++ 5 files changed, 145 insertions(+), 13 deletions(-) create mode 100644 tests/ui/lang/asm/block_tracking_fail.rs create mode 100644 tests/ui/lang/asm/block_tracking_fail.stderr create mode 100644 tests/ui/lang/asm/block_tracking_pass.rs diff --git a/crates/rustc_codegen_spirv/src/builder/spirv_asm.rs b/crates/rustc_codegen_spirv/src/builder/spirv_asm.rs index d4b6bf4763..fbba7e9c9e 100644 --- a/crates/rustc_codegen_spirv/src/builder/spirv_asm.rs +++ b/crates/rustc_codegen_spirv/src/builder/spirv_asm.rs @@ -146,14 +146,36 @@ impl<'a, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'tcx> { id_to_type_map.insert(value.def(self), value.ty); } } + + let mut asm_block = AsmBlock::Open; for line in tokens { self.codegen_asm( &mut id_map, &mut defined_ids, &mut id_to_type_map, + &mut asm_block, line.into_iter(), ); } + + match (options.contains(InlineAsmOptions::NORETURN), asm_block) { + (true, AsmBlock::Open) => { + self.err("`noreturn` requires a terminator at the end"); + } + (true, AsmBlock::End(_)) => { + let label = self.emit().id(); + self.emit() + .insert_into_block( + dr::InsertPoint::End, + dr::Instruction::new(Op::Label, None, Some(label), vec![]), + ) + .unwrap(); + } + (false, AsmBlock::Open) => (), + (false, AsmBlock::End(terminator)) => { + self.err(&format!("trailing terminator {:?} requires `options(noreturn)`", terminator)); + } + } for (id, num) in id_map { if !defined_ids.contains(&num) { self.err(&format!("%{} is used but not defined", id)); @@ -183,6 +205,11 @@ enum OutRegister<'a> { Place(PlaceRef<'a, SpirvValue>), } +enum AsmBlock { + Open, + End(Op), +} + impl<'cx, 'tcx> Builder<'cx, 'tcx> { fn lex_word<'a>(&self, line: &mut std::str::Chars<'a>) -> Option> { loop { @@ -247,6 +274,7 @@ impl<'cx, 'tcx> Builder<'cx, 'tcx> { &mut self, id_map: &mut FxHashMap<&str, Word>, defined_ids: &mut FxHashSet, + asm_block: &mut AsmBlock, inst: dr::Instruction, ) { // Types declared must be registered in our type system. @@ -339,17 +367,22 @@ impl<'cx, 'tcx> Builder<'cx, 'tcx> { .insert_into_block(dr::InsertPoint::End, inst) .unwrap(); - // Return or abort terminators will also end the current block and start a new one. - // The new block is transparent to the actual builder cursor. - if reflect::is_return_or_abort(op) { - let label = self.emit().id(); - self.emit() - .insert_into_block( - dr::InsertPoint::End, - dr::Instruction::new(Op::Label, None, Some(label), vec![]), - ) - .unwrap(); - } + *asm_block = match *asm_block { + AsmBlock::Open => { + if reflect::is_block_terminator(op) { + AsmBlock::End(op) + } else { + AsmBlock::Open + } + } + AsmBlock::End(terminator) => { + if op != Op::Label { + self.err(&format!("expected OpLabel after terminator {:?}", terminator)); + } + + AsmBlock::Open + } + }; return; } @@ -370,6 +403,7 @@ impl<'cx, 'tcx> Builder<'cx, 'tcx> { id_map: &mut FxHashMap<&'a str, Word>, defined_ids: &mut FxHashSet, id_to_type_map: &mut FxHashMap, + asm_block: &mut AsmBlock, mut tokens: impl Iterator>, ) where 'cx: 'a, @@ -446,7 +480,7 @@ impl<'cx, 'tcx> Builder<'cx, 'tcx> { if let Some(result_type) = instruction.result_type { id_to_type_map.insert(instruction.result_id.unwrap(), result_type); } - self.insert_inst(id_map, defined_ids, instruction); + self.insert_inst(id_map, defined_ids, asm_block, instruction); if let Some(OutRegister::Place(place)) = out_register { self.emit() .store( diff --git a/crates/spirv-std/src/lib.rs b/crates/spirv-std/src/lib.rs index f104456f82..0516578171 100644 --- a/crates/spirv-std/src/lib.rs +++ b/crates/spirv-std/src/lib.rs @@ -118,7 +118,7 @@ pub use glam; #[cfg(all(not(test), target_arch = "spirv"))] #[panic_handler] fn panic(_: &core::panic::PanicInfo<'_>) -> ! { - unsafe { asm!("", options(noreturn)) } + loop { } } #[cfg(all(not(test), target_arch = "spirv"))] diff --git a/tests/ui/lang/asm/block_tracking_fail.rs b/tests/ui/lang/asm/block_tracking_fail.rs new file mode 100644 index 0000000000..91340daec8 --- /dev/null +++ b/tests/ui/lang/asm/block_tracking_fail.rs @@ -0,0 +1,41 @@ +// Tests validating tracking of basic blocks +// within the `asm!` macro. +// build-fail + +use spirv_std as _; + +// Active basic block with `noreturn`. +fn asm_noreturn_open() { + unsafe { + asm!( + options(noreturn) + ); + } +} + +// No active basic block without `noreturn`. +fn asm_closed() { + unsafe { + asm!( + "OpUnreachable", + ); + } +} + +// Invalid op after terminator +fn asm_invalid_op_terminator(x: f32) { + unsafe { + asm!( + "OpKill", + "%sum = OpFAdd _ {x} {x}", + x = in(reg) x, + ); + } +} + +#[spirv(fragment)] +pub fn main() { + asm_closed(); + asm_noreturn_open(); + asm_invalid_op_terminator(1.0); +} diff --git a/tests/ui/lang/asm/block_tracking_fail.stderr b/tests/ui/lang/asm/block_tracking_fail.stderr new file mode 100644 index 0000000000..9e1396af29 --- /dev/null +++ b/tests/ui/lang/asm/block_tracking_fail.stderr @@ -0,0 +1,29 @@ +error: `noreturn` requires a terminator at the end + --> $DIR/block_tracking_fail.rs:10:9 + | +10 | / asm!( +11 | | "%unused = OpLabel", +12 | | options(noreturn), +13 | | ); + | |__________^ + +error: trailing terminator Unreachable requires `options(noreturn)` + --> $DIR/block_tracking_fail.rs:20:9 + | +20 | / asm!( +21 | | "OpUnreachable", +22 | | ); + | |__________^ + +error: expected OpLabel after terminator Kill + --> $DIR/block_tracking_fail.rs:29:9 + | +29 | / asm!( +30 | | "OpKill", +31 | | "%sum = OpFAdd _ {x} {x}", +32 | | x = in(reg) x, +33 | | ); + | |__________^ + +error: aborting due to 3 previous errors + diff --git a/tests/ui/lang/asm/block_tracking_pass.rs b/tests/ui/lang/asm/block_tracking_pass.rs new file mode 100644 index 0000000000..1e2ca83e7f --- /dev/null +++ b/tests/ui/lang/asm/block_tracking_pass.rs @@ -0,0 +1,28 @@ +// Tests validating tracking of basic blocks +// within the `asm!` macro. +// build-pass + +use spirv_std as _; + +fn asm_label() { + unsafe { + asm!( + "%unused = OpLabel", + ); + } +} + +fn asm_noreturn_single() -> ! { + unsafe { + asm!( + "OpKill", + options(noreturn), + ); + } +} + +#[spirv(fragment)] +pub fn main() { + asm_label(); + // asm_noreturn_single(); +} From 884762c4fdf8fd76fa9493bb2194bd2ee0b8ed3d Mon Sep 17 00:00:00 2001 From: msiglreith Date: Thu, 12 Aug 2021 21:32:13 +0200 Subject: [PATCH 4/5] fix tests and add few comments --- crates/rustc_codegen_spirv/src/builder/spirv_asm.rs | 12 ++++++++++-- crates/spirv-std/src/lib.rs | 2 +- tests/ui/lang/asm/block_tracking_pass.rs | 7 ++++--- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/crates/rustc_codegen_spirv/src/builder/spirv_asm.rs b/crates/rustc_codegen_spirv/src/builder/spirv_asm.rs index fbba7e9c9e..59dc388e9d 100644 --- a/crates/rustc_codegen_spirv/src/builder/spirv_asm.rs +++ b/crates/rustc_codegen_spirv/src/builder/spirv_asm.rs @@ -163,6 +163,8 @@ impl<'a, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'tcx> { self.err("`noreturn` requires a terminator at the end"); } (true, AsmBlock::End(_)) => { + // `noreturn` appends an `OpUnreachable` after the asm block. + // This requires starting a new block for this. let label = self.emit().id(); self.emit() .insert_into_block( @@ -173,7 +175,10 @@ impl<'a, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'tcx> { } (false, AsmBlock::Open) => (), (false, AsmBlock::End(terminator)) => { - self.err(&format!("trailing terminator {:?} requires `options(noreturn)`", terminator)); + self.err(&format!( + "trailing terminator {:?} requires `options(noreturn)`", + terminator + )); } } for (id, num) in id_map { @@ -377,7 +382,10 @@ impl<'cx, 'tcx> Builder<'cx, 'tcx> { } AsmBlock::End(terminator) => { if op != Op::Label { - self.err(&format!("expected OpLabel after terminator {:?}", terminator)); + self.err(&format!( + "expected OpLabel after terminator {:?}", + terminator + )); } AsmBlock::Open diff --git a/crates/spirv-std/src/lib.rs b/crates/spirv-std/src/lib.rs index 0516578171..8c4c2080c6 100644 --- a/crates/spirv-std/src/lib.rs +++ b/crates/spirv-std/src/lib.rs @@ -118,7 +118,7 @@ pub use glam; #[cfg(all(not(test), target_arch = "spirv"))] #[panic_handler] fn panic(_: &core::panic::PanicInfo<'_>) -> ! { - loop { } + loop {} } #[cfg(all(not(test), target_arch = "spirv"))] diff --git a/tests/ui/lang/asm/block_tracking_pass.rs b/tests/ui/lang/asm/block_tracking_pass.rs index 1e2ca83e7f..fef96015ce 100644 --- a/tests/ui/lang/asm/block_tracking_pass.rs +++ b/tests/ui/lang/asm/block_tracking_pass.rs @@ -7,7 +7,8 @@ use spirv_std as _; fn asm_label() { unsafe { asm!( - "%unused = OpLabel", + "OpReturn", // close active block + "%unused = OpLabel", // open new block ); } } @@ -15,7 +16,7 @@ fn asm_label() { fn asm_noreturn_single() -> ! { unsafe { asm!( - "OpKill", + "OpKill", // close active block options(noreturn), ); } @@ -24,5 +25,5 @@ fn asm_noreturn_single() -> ! { #[spirv(fragment)] pub fn main() { asm_label(); - // asm_noreturn_single(); + asm_noreturn_single(); } From a9aa489c68d68b69d006faa02cabd4deacbbfd67 Mon Sep 17 00:00:00 2001 From: msiglreith Date: Thu, 12 Aug 2021 23:20:20 +0200 Subject: [PATCH 5/5] fix tests --- tests/ui/lang/asm/block_tracking_fail.rs | 4 +-- tests/ui/lang/asm/block_tracking_fail.stderr | 27 +++++++++----------- 2 files changed, 13 insertions(+), 18 deletions(-) diff --git a/tests/ui/lang/asm/block_tracking_fail.rs b/tests/ui/lang/asm/block_tracking_fail.rs index 91340daec8..0a2b3ec820 100644 --- a/tests/ui/lang/asm/block_tracking_fail.rs +++ b/tests/ui/lang/asm/block_tracking_fail.rs @@ -7,9 +7,7 @@ use spirv_std as _; // Active basic block with `noreturn`. fn asm_noreturn_open() { unsafe { - asm!( - options(noreturn) - ); + asm!("", options(noreturn)); } } diff --git a/tests/ui/lang/asm/block_tracking_fail.stderr b/tests/ui/lang/asm/block_tracking_fail.stderr index 9e1396af29..eff99b743e 100644 --- a/tests/ui/lang/asm/block_tracking_fail.stderr +++ b/tests/ui/lang/asm/block_tracking_fail.stderr @@ -1,28 +1,25 @@ error: `noreturn` requires a terminator at the end --> $DIR/block_tracking_fail.rs:10:9 | -10 | / asm!( -11 | | "%unused = OpLabel", -12 | | options(noreturn), -13 | | ); - | |__________^ +10 | asm!("", options(noreturn)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: trailing terminator Unreachable requires `options(noreturn)` - --> $DIR/block_tracking_fail.rs:20:9 + --> $DIR/block_tracking_fail.rs:17:9 | -20 | / asm!( -21 | | "OpUnreachable", -22 | | ); +17 | / asm!( +18 | | "OpUnreachable", +19 | | ); | |__________^ error: expected OpLabel after terminator Kill - --> $DIR/block_tracking_fail.rs:29:9 + --> $DIR/block_tracking_fail.rs:26:9 | -29 | / asm!( -30 | | "OpKill", -31 | | "%sum = OpFAdd _ {x} {x}", -32 | | x = in(reg) x, -33 | | ); +26 | / asm!( +27 | | "OpKill", +28 | | "%sum = OpFAdd _ {x} {x}", +29 | | x = in(reg) x, +30 | | ); | |__________^ error: aborting due to 3 previous errors