Skip to content

Commit cecffdc

Browse files
committed
Fix const handling and add tests for const operands
1 parent 6f8be8c commit cecffdc

File tree

2 files changed

+184
-91
lines changed

2 files changed

+184
-91
lines changed

src/librustc_codegen_ssa/mir/block.rs

+128-91
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use rustc_ast::ast;
1313
use rustc_hir::lang_items;
1414
use rustc_index::vec::Idx;
1515
use rustc_middle::mir;
16+
use rustc_middle::mir::interpret::{AllocId, ConstValue, Pointer, Scalar};
1617
use rustc_middle::mir::AssertKind;
1718
use rustc_middle::ty::layout::{FnAbiExt, HasTyCtxt};
1819
use rustc_middle::ty::{self, Instance, Ty, TypeFoldable};
@@ -821,6 +822,123 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
821822
cleanup,
822823
);
823824
}
825+
826+
fn codegen_asm_terminator(
827+
&mut self,
828+
helper: TerminatorCodegenHelper<'tcx>,
829+
mut bx: Bx,
830+
terminator: &mir::Terminator<'tcx>,
831+
template: &[ast::InlineAsmTemplatePiece],
832+
operands: &[mir::InlineAsmOperand<'tcx>],
833+
options: ast::InlineAsmOptions,
834+
destination: Option<mir::BasicBlock>,
835+
) {
836+
let span = terminator.source_info.span;
837+
838+
let operands: Vec<_> = operands
839+
.iter()
840+
.map(|op| match *op {
841+
mir::InlineAsmOperand::In { reg, ref value } => {
842+
let value = self.codegen_operand(&mut bx, value);
843+
InlineAsmOperandRef::In { reg, value }
844+
}
845+
mir::InlineAsmOperand::Out { reg, late, ref place } => {
846+
let place = place.map(|place| self.codegen_place(&mut bx, place.as_ref()));
847+
InlineAsmOperandRef::Out { reg, late, place }
848+
}
849+
mir::InlineAsmOperand::InOut { reg, late, ref in_value, ref out_place } => {
850+
let in_value = self.codegen_operand(&mut bx, in_value);
851+
let out_place =
852+
out_place.map(|out_place| self.codegen_place(&mut bx, out_place.as_ref()));
853+
InlineAsmOperandRef::InOut { reg, late, in_value, out_place }
854+
}
855+
mir::InlineAsmOperand::Const { ref value } => {
856+
if let mir::Operand::Constant(constant) = value {
857+
let const_value = self
858+
.eval_mir_constant(constant)
859+
.unwrap_or_else(|_| span_bug!(span, "asm const cannot be resolved"));
860+
let ty = constant.literal.ty;
861+
let size = bx.layout_of(ty).size;
862+
let scalar = match const_value {
863+
// Promoted constants are evaluated into a ByRef instead of a Scalar,
864+
// but we want the scalar value here.
865+
ConstValue::ByRef { alloc, offset } => {
866+
let ptr = Pointer::new(AllocId(0), offset);
867+
alloc
868+
.read_scalar(&bx, ptr, size)
869+
.and_then(|s| s.not_undef())
870+
.unwrap_or_else(|e| {
871+
bx.tcx().sess.span_err(
872+
span,
873+
&format!("Could not evaluate asm const: {}", e),
874+
);
875+
876+
// We are erroring out, just emit a dummy constant.
877+
Scalar::from_u64(0)
878+
})
879+
}
880+
_ => span_bug!(span, "expected ByRef for promoted asm const"),
881+
};
882+
let value = scalar.assert_bits(size);
883+
let string = match ty.kind {
884+
ty::Uint(_) => value.to_string(),
885+
ty::Int(int_ty) => {
886+
match int_ty.normalize(bx.tcx().sess.target.ptr_width) {
887+
ast::IntTy::I8 => (value as i8).to_string(),
888+
ast::IntTy::I16 => (value as i16).to_string(),
889+
ast::IntTy::I32 => (value as i32).to_string(),
890+
ast::IntTy::I64 => (value as i64).to_string(),
891+
ast::IntTy::I128 => (value as i128).to_string(),
892+
ast::IntTy::Isize => unreachable!(),
893+
}
894+
}
895+
ty::Float(ast::FloatTy::F32) => {
896+
f32::from_bits(value as u32).to_string()
897+
}
898+
ty::Float(ast::FloatTy::F64) => {
899+
f64::from_bits(value as u64).to_string()
900+
}
901+
_ => span_bug!(span, "asm const has bad type {}", ty),
902+
};
903+
InlineAsmOperandRef::Const { string }
904+
} else {
905+
span_bug!(span, "asm const is not a constant");
906+
}
907+
}
908+
mir::InlineAsmOperand::SymFn { ref value } => {
909+
let literal = self.monomorphize(&value.literal);
910+
if let ty::FnDef(def_id, substs) = literal.ty.kind {
911+
let instance = ty::Instance::resolve(
912+
bx.tcx(),
913+
ty::ParamEnv::reveal_all(),
914+
def_id,
915+
substs,
916+
)
917+
.unwrap()
918+
.unwrap();
919+
InlineAsmOperandRef::SymFn { instance }
920+
} else {
921+
span_bug!(span, "invalid type for asm sym (fn)");
922+
}
923+
}
924+
mir::InlineAsmOperand::SymStatic { ref value } => {
925+
if let Some(def_id) = value.check_static_ptr(bx.tcx()) {
926+
InlineAsmOperandRef::SymStatic { def_id }
927+
} else {
928+
span_bug!(span, "invalid type for asm sym (static)");
929+
}
930+
}
931+
})
932+
.collect();
933+
934+
bx.codegen_inline_asm(template, &operands, options, span);
935+
936+
if let Some(target) = destination {
937+
helper.funclet_br(self, &mut bx, target);
938+
} else {
939+
bx.unreachable();
940+
}
941+
}
824942
}
825943

826944
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> {
9161034
bug!("borrowck false edges in codegen")
9171035
}
9181036

919-
mir::TerminatorKind::InlineAsm { template, ref operands, options, ref destination } => {
920-
let span = terminator.source_info.span;
921-
922-
let operands: Vec<_> = operands
923-
.iter()
924-
.map(|op| match *op {
925-
mir::InlineAsmOperand::In { reg, ref value } => {
926-
let value = self.codegen_operand(&mut bx, value);
927-
InlineAsmOperandRef::In { reg, value }
928-
}
929-
mir::InlineAsmOperand::Out { reg, late, ref place } => {
930-
let place =
931-
place.map(|place| self.codegen_place(&mut bx, place.as_ref()));
932-
InlineAsmOperandRef::Out { reg, late, place }
933-
}
934-
mir::InlineAsmOperand::InOut { reg, late, ref in_value, ref out_place } => {
935-
let in_value = self.codegen_operand(&mut bx, in_value);
936-
let out_place = out_place
937-
.map(|out_place| self.codegen_place(&mut bx, out_place.as_ref()));
938-
InlineAsmOperandRef::InOut { reg, late, in_value, out_place }
939-
}
940-
mir::InlineAsmOperand::Const { ref value } => {
941-
if let mir::Operand::Constant(constant) = value {
942-
let const_value =
943-
self.eval_mir_constant(constant).unwrap_or_else(|_| {
944-
span_bug!(span, "asm const cannot be resolved")
945-
});
946-
let ty = constant.literal.ty;
947-
let value = const_value
948-
.try_to_bits_for_ty(bx.tcx(), ty::ParamEnv::reveal_all(), ty)
949-
.unwrap_or_else(|| {
950-
span_bug!(span, "asm const has non-scalar value")
951-
});
952-
let string = match ty.kind {
953-
ty::Uint(_) => value.to_string(),
954-
ty::Int(int_ty) => {
955-
match int_ty.normalize(bx.tcx().sess.target.ptr_width) {
956-
ast::IntTy::I8 => (value as i8).to_string(),
957-
ast::IntTy::I16 => (value as i16).to_string(),
958-
ast::IntTy::I32 => (value as i32).to_string(),
959-
ast::IntTy::I64 => (value as i64).to_string(),
960-
ast::IntTy::I128 => (value as i128).to_string(),
961-
ast::IntTy::Isize => unreachable!(),
962-
}
963-
}
964-
ty::Float(ast::FloatTy::F32) => {
965-
f32::from_bits(value as u32).to_string()
966-
}
967-
ty::Float(ast::FloatTy::F64) => {
968-
f64::from_bits(value as u64).to_string()
969-
}
970-
_ => span_bug!(span, "asm const has bad type {}", ty),
971-
};
972-
InlineAsmOperandRef::Const { string }
973-
} else {
974-
span_bug!(span, "asm const is not a constant");
975-
}
976-
}
977-
mir::InlineAsmOperand::SymFn { ref value } => {
978-
let literal = self.monomorphize(&value.literal);
979-
if let ty::FnDef(def_id, substs) = literal.ty.kind {
980-
let instance = ty::Instance::resolve(
981-
bx.tcx(),
982-
ty::ParamEnv::reveal_all(),
983-
def_id,
984-
substs,
985-
)
986-
.unwrap()
987-
.unwrap();
988-
InlineAsmOperandRef::SymFn { instance }
989-
} else {
990-
span_bug!(span, "invalid type for asm sym (fn)");
991-
}
992-
}
993-
mir::InlineAsmOperand::SymStatic { ref value } => {
994-
if let Some(def_id) = value.check_static_ptr(bx.tcx()) {
995-
InlineAsmOperandRef::SymStatic { def_id }
996-
} else {
997-
span_bug!(span, "invalid type for asm sym (static)");
998-
}
999-
}
1000-
})
1001-
.collect();
1002-
1003-
bx.codegen_inline_asm(template, &operands, options, span);
1004-
1005-
if let Some(target) = destination {
1006-
helper.funclet_br(self, &mut bx, *target);
1007-
} else {
1008-
bx.unreachable();
1009-
}
1037+
mir::TerminatorKind::InlineAsm { template, ref operands, options, destination } => {
1038+
self.codegen_asm_terminator(
1039+
helper,
1040+
bx,
1041+
terminator,
1042+
template,
1043+
operands,
1044+
options,
1045+
destination,
1046+
);
10101047
}
10111048
}
10121049
}

src/test/ui/asm/const.rs

+56
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
// no-system-llvm
2+
// only-x86_64
3+
// run-pass
4+
5+
#![feature(asm)]
6+
7+
use std::mem::size_of;
8+
9+
trait Proj {
10+
const C: usize;
11+
}
12+
impl Proj for i8 {
13+
const C: usize = 8;
14+
}
15+
impl Proj for i16 {
16+
const C: usize = 16;
17+
}
18+
19+
const fn constfn(x: usize) -> usize {
20+
x
21+
}
22+
23+
fn generic<T: Proj>() {
24+
unsafe {
25+
let a: usize;
26+
asm!("mov {}, {}", out(reg) a, const size_of::<T>());
27+
assert_eq!(a, size_of::<T>());
28+
29+
let b: usize;
30+
asm!("mov {}, {}", out(reg) b, const size_of::<T>() + constfn(5));
31+
assert_eq!(b, size_of::<T>() + 5);
32+
33+
let c: usize;
34+
asm!("mov {}, {}", out(reg) c, const T::C);
35+
assert_eq!(c, T::C);
36+
}
37+
}
38+
39+
fn main() {
40+
unsafe {
41+
let a: usize;
42+
asm!("mov {}, {}", out(reg) a, const 5);
43+
assert_eq!(a, 5);
44+
45+
let b: usize;
46+
asm!("mov {}, {}", out(reg) b, const constfn(5));
47+
assert_eq!(b, 5);
48+
49+
let c: usize;
50+
asm!("mov {}, {}", out(reg) c, const constfn(5) + constfn(5));
51+
assert_eq!(c, 10);
52+
}
53+
54+
generic::<i8>();
55+
generic::<i16>();
56+
}

0 commit comments

Comments
 (0)