about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorAmanieu d'Antras <amanieu@gmail.com>2020-05-11 17:53:32 +0100
committerAmanieu d'Antras <amanieu@gmail.com>2020-05-18 14:41:35 +0100
commitcecffdc1d74718444b6654b120dcd57dcbad018f (patch)
tree1c05920507b1ac624311a3e3bea288a11a7e4cec /src
parent6f8be8cc8c826a4d2759e26c6514fcfcf076a105 (diff)
Fix const handling and add tests for const operands
Diffstat (limited to 'src')
-rw-r--r--src/librustc_codegen_ssa/mir/block.rs219
-rw-r--r--src/test/ui/asm/const.rs56
2 files changed, 184 insertions, 91 deletions
diff --git a/src/librustc_codegen_ssa/mir/block.rs b/src/librustc_codegen_ssa/mir/block.rs
index 923fcd326a2..b487ed8dea8 100644
--- a/src/librustc_codegen_ssa/mir/block.rs
+++ b/src/librustc_codegen_ssa/mir/block.rs
@@ -13,6 +13,7 @@ use rustc_ast::ast;
 use rustc_hir::lang_items;
 use rustc_index::vec::Idx;
 use rustc_middle::mir;
+use rustc_middle::mir::interpret::{AllocId, ConstValue, Pointer, Scalar};
 use rustc_middle::mir::AssertKind;
 use rustc_middle::ty::layout::{FnAbiExt, HasTyCtxt};
 use rustc_middle::ty::{self, Instance, Ty, TypeFoldable};
@@ -821,6 +822,123 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             cleanup,
         );
     }
+
+    fn codegen_asm_terminator(
+        &mut self,
+        helper: TerminatorCodegenHelper<'tcx>,
+        mut bx: Bx,
+        terminator: &mir::Terminator<'tcx>,
+        template: &[ast::InlineAsmTemplatePiece],
+        operands: &[mir::InlineAsmOperand<'tcx>],
+        options: ast::InlineAsmOptions,
+        destination: Option<mir::BasicBlock>,
+    ) {
+        let span = terminator.source_info.span;
+
+        let operands: Vec<_> = operands
+            .iter()
+            .map(|op| match *op {
+                mir::InlineAsmOperand::In { reg, ref value } => {
+                    let value = self.codegen_operand(&mut bx, value);
+                    InlineAsmOperandRef::In { reg, value }
+                }
+                mir::InlineAsmOperand::Out { reg, late, ref place } => {
+                    let place = place.map(|place| self.codegen_place(&mut bx, place.as_ref()));
+                    InlineAsmOperandRef::Out { reg, late, place }
+                }
+                mir::InlineAsmOperand::InOut { reg, late, ref in_value, ref out_place } => {
+                    let in_value = self.codegen_operand(&mut bx, in_value);
+                    let out_place =
+                        out_place.map(|out_place| self.codegen_place(&mut bx, out_place.as_ref()));
+                    InlineAsmOperandRef::InOut { reg, late, in_value, out_place }
+                }
+                mir::InlineAsmOperand::Const { ref value } => {
+                    if let mir::Operand::Constant(constant) = value {
+                        let const_value = self
+                            .eval_mir_constant(constant)
+                            .unwrap_or_else(|_| span_bug!(span, "asm const cannot be resolved"));
+                        let ty = constant.literal.ty;
+                        let size = bx.layout_of(ty).size;
+                        let scalar = match const_value {
+                            // Promoted constants are evaluated into a ByRef instead of a Scalar,
+                            // but we want the scalar value here.
+                            ConstValue::ByRef { alloc, offset } => {
+                                let ptr = Pointer::new(AllocId(0), offset);
+                                alloc
+                                    .read_scalar(&bx, ptr, size)
+                                    .and_then(|s| s.not_undef())
+                                    .unwrap_or_else(|e| {
+                                        bx.tcx().sess.span_err(
+                                            span,
+                                            &format!("Could not evaluate asm const: {}", e),
+                                        );
+
+                                        // We are erroring out, just emit a dummy constant.
+                                        Scalar::from_u64(0)
+                                    })
+                            }
+                            _ => span_bug!(span, "expected ByRef for promoted asm const"),
+                        };
+                        let value = scalar.assert_bits(size);
+                        let string = match ty.kind {
+                            ty::Uint(_) => value.to_string(),
+                            ty::Int(int_ty) => {
+                                match int_ty.normalize(bx.tcx().sess.target.ptr_width) {
+                                    ast::IntTy::I8 => (value as i8).to_string(),
+                                    ast::IntTy::I16 => (value as i16).to_string(),
+                                    ast::IntTy::I32 => (value as i32).to_string(),
+                                    ast::IntTy::I64 => (value as i64).to_string(),
+                                    ast::IntTy::I128 => (value as i128).to_string(),
+                                    ast::IntTy::Isize => unreachable!(),
+                                }
+                            }
+                            ty::Float(ast::FloatTy::F32) => {
+                                f32::from_bits(value as u32).to_string()
+                            }
+                            ty::Float(ast::FloatTy::F64) => {
+                                f64::from_bits(value as u64).to_string()
+                            }
+                            _ => span_bug!(span, "asm const has bad type {}", ty),
+                        };
+                        InlineAsmOperandRef::Const { string }
+                    } else {
+                        span_bug!(span, "asm const is not a constant");
+                    }
+                }
+                mir::InlineAsmOperand::SymFn { ref value } => {
+                    let literal = self.monomorphize(&value.literal);
+                    if let ty::FnDef(def_id, substs) = literal.ty.kind {
+                        let instance = ty::Instance::resolve(
+                            bx.tcx(),
+                            ty::ParamEnv::reveal_all(),
+                            def_id,
+                            substs,
+                        )
+                        .unwrap()
+                        .unwrap();
+                        InlineAsmOperandRef::SymFn { instance }
+                    } else {
+                        span_bug!(span, "invalid type for asm sym (fn)");
+                    }
+                }
+                mir::InlineAsmOperand::SymStatic { ref value } => {
+                    if let Some(def_id) = value.check_static_ptr(bx.tcx()) {
+                        InlineAsmOperandRef::SymStatic { def_id }
+                    } else {
+                        span_bug!(span, "invalid type for asm sym (static)");
+                    }
+                }
+            })
+            .collect();
+
+        bx.codegen_inline_asm(template, &operands, options, span);
+
+        if let Some(target) = destination {
+            helper.funclet_br(self, &mut bx, target);
+        } else {
+            bx.unreachable();
+        }
+    }
 }
 
 impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
@@ -916,97 +1034,16 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                 bug!("borrowck false edges in codegen")
             }
 
-            mir::TerminatorKind::InlineAsm { template, ref operands, options, ref destination } => {
-                let span = terminator.source_info.span;
-
-                let operands: Vec<_> = operands
-                    .iter()
-                    .map(|op| match *op {
-                        mir::InlineAsmOperand::In { reg, ref value } => {
-                            let value = self.codegen_operand(&mut bx, value);
-                            InlineAsmOperandRef::In { reg, value }
-                        }
-                        mir::InlineAsmOperand::Out { reg, late, ref place } => {
-                            let place =
-                                place.map(|place| self.codegen_place(&mut bx, place.as_ref()));
-                            InlineAsmOperandRef::Out { reg, late, place }
-                        }
-                        mir::InlineAsmOperand::InOut { reg, late, ref in_value, ref out_place } => {
-                            let in_value = self.codegen_operand(&mut bx, in_value);
-                            let out_place = out_place
-                                .map(|out_place| self.codegen_place(&mut bx, out_place.as_ref()));
-                            InlineAsmOperandRef::InOut { reg, late, in_value, out_place }
-                        }
-                        mir::InlineAsmOperand::Const { ref value } => {
-                            if let mir::Operand::Constant(constant) = value {
-                                let const_value =
-                                    self.eval_mir_constant(constant).unwrap_or_else(|_| {
-                                        span_bug!(span, "asm const cannot be resolved")
-                                    });
-                                let ty = constant.literal.ty;
-                                let value = const_value
-                                    .try_to_bits_for_ty(bx.tcx(), ty::ParamEnv::reveal_all(), ty)
-                                    .unwrap_or_else(|| {
-                                        span_bug!(span, "asm const has non-scalar value")
-                                    });
-                                let string = match ty.kind {
-                                    ty::Uint(_) => value.to_string(),
-                                    ty::Int(int_ty) => {
-                                        match int_ty.normalize(bx.tcx().sess.target.ptr_width) {
-                                            ast::IntTy::I8 => (value as i8).to_string(),
-                                            ast::IntTy::I16 => (value as i16).to_string(),
-                                            ast::IntTy::I32 => (value as i32).to_string(),
-                                            ast::IntTy::I64 => (value as i64).to_string(),
-                                            ast::IntTy::I128 => (value as i128).to_string(),
-                                            ast::IntTy::Isize => unreachable!(),
-                                        }
-                                    }
-                                    ty::Float(ast::FloatTy::F32) => {
-                                        f32::from_bits(value as u32).to_string()
-                                    }
-                                    ty::Float(ast::FloatTy::F64) => {
-                                        f64::from_bits(value as u64).to_string()
-                                    }
-                                    _ => span_bug!(span, "asm const has bad type {}", ty),
-                                };
-                                InlineAsmOperandRef::Const { string }
-                            } else {
-                                span_bug!(span, "asm const is not a constant");
-                            }
-                        }
-                        mir::InlineAsmOperand::SymFn { ref value } => {
-                            let literal = self.monomorphize(&value.literal);
-                            if let ty::FnDef(def_id, substs) = literal.ty.kind {
-                                let instance = ty::Instance::resolve(
-                                    bx.tcx(),
-                                    ty::ParamEnv::reveal_all(),
-                                    def_id,
-                                    substs,
-                                )
-                                .unwrap()
-                                .unwrap();
-                                InlineAsmOperandRef::SymFn { instance }
-                            } else {
-                                span_bug!(span, "invalid type for asm sym (fn)");
-                            }
-                        }
-                        mir::InlineAsmOperand::SymStatic { ref value } => {
-                            if let Some(def_id) = value.check_static_ptr(bx.tcx()) {
-                                InlineAsmOperandRef::SymStatic { def_id }
-                            } else {
-                                span_bug!(span, "invalid type for asm sym (static)");
-                            }
-                        }
-                    })
-                    .collect();
-
-                bx.codegen_inline_asm(template, &operands, options, span);
-
-                if let Some(target) = destination {
-                    helper.funclet_br(self, &mut bx, *target);
-                } else {
-                    bx.unreachable();
-                }
+            mir::TerminatorKind::InlineAsm { template, ref operands, options, destination } => {
+                self.codegen_asm_terminator(
+                    helper,
+                    bx,
+                    terminator,
+                    template,
+                    operands,
+                    options,
+                    destination,
+                );
             }
         }
     }
diff --git a/src/test/ui/asm/const.rs b/src/test/ui/asm/const.rs
new file mode 100644
index 00000000000..e08da24f44a
--- /dev/null
+++ b/src/test/ui/asm/const.rs
@@ -0,0 +1,56 @@
+// no-system-llvm
+// only-x86_64
+// run-pass
+
+#![feature(asm)]
+
+use std::mem::size_of;
+
+trait Proj {
+    const C: usize;
+}
+impl Proj for i8 {
+    const C: usize = 8;
+}
+impl Proj for i16 {
+    const C: usize = 16;
+}
+
+const fn constfn(x: usize) -> usize {
+    x
+}
+
+fn generic<T: Proj>() {
+    unsafe {
+        let a: usize;
+        asm!("mov {}, {}", out(reg) a, const size_of::<T>());
+        assert_eq!(a, size_of::<T>());
+
+        let b: usize;
+        asm!("mov {}, {}", out(reg) b, const size_of::<T>() + constfn(5));
+        assert_eq!(b, size_of::<T>() + 5);
+
+        let c: usize;
+        asm!("mov {}, {}", out(reg) c, const T::C);
+        assert_eq!(c, T::C);
+    }
+}
+
+fn main() {
+    unsafe {
+        let a: usize;
+        asm!("mov {}, {}", out(reg) a, const 5);
+        assert_eq!(a, 5);
+
+        let b: usize;
+        asm!("mov {}, {}", out(reg) b, const constfn(5));
+        assert_eq!(b, 5);
+
+        let c: usize;
+        asm!("mov {}, {}", out(reg) c, const constfn(5) + constfn(5));
+        assert_eq!(c, 10);
+    }
+
+    generic::<i8>();
+    generic::<i16>();
+}