Skip to content

Commit fc2244a

Browse files
committed
Encode strings as Symbol in value tree representation
1 parent bdfe567 commit fc2244a

28 files changed

+120
-113
lines changed

compiler/rustc_codegen_cranelift/src/constant.rs

+14-9
Original file line numberDiff line numberDiff line change
@@ -154,13 +154,8 @@ pub(crate) fn codegen_valtree<'tcx>(
154154
) -> CValue<'tcx> {
155155
let layout = fx.layout_of(ty);
156156
let tcx = fx.tcx;
157-
let mut encode_slice = |valtree: ty::ValTree<'_>| {
158-
let s: Vec<u8> = valtree
159-
.unwrap_branch()
160-
.iter()
161-
.map(|b| u8::try_from(b.unwrap_leaf()).unwrap())
162-
.collect();
163-
let alloc_id = fx.tcx.allocate_bytes(&s);
157+
let mut encode_slice = |s| {
158+
let alloc_id = fx.tcx.allocate_bytes(s);
164159

165160
let ptr = pointer_for_alloc_id(fx, alloc_id, Mutability::Not).get_addr(fx);
166161
let len = fx.bcx.ins().iconst(fx.pointer_type, i64::try_from(s.len()).unwrap());
@@ -169,8 +164,18 @@ pub(crate) fn codegen_valtree<'tcx>(
169164

170165
match *ty.kind() {
171166
ty::Ref(_, pointee, _) => match *pointee.kind() {
172-
ty::Str => encode_slice(valtree),
173-
ty::Slice(elem_ty) if elem_ty == tcx.types.u8 => encode_slice(valtree),
167+
ty::Str => {
168+
let s = valtree.unwrap_str().as_str();
169+
encode_slice(s.as_bytes())
170+
}
171+
ty::Slice(elem_ty) if elem_ty == tcx.types.u8 => {
172+
let s: Vec<u8> = valtree
173+
.unwrap_branch()
174+
.iter()
175+
.map(|b| u8::try_from(b.unwrap_leaf()).unwrap())
176+
.collect();
177+
encode_slice(&s)
178+
}
174179
ty::Array(elem_ty, _) if elem_ty == tcx.types.u8 => {
175180
let s: Vec<u8> = valtree
176181
.unwrap_branch()

compiler/rustc_codegen_ssa/src/mir/operand.rs

+14-9
Original file line numberDiff line numberDiff line change
@@ -79,13 +79,8 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
7979
return OperandRef::new_zst(bx, layout);
8080
}
8181

82-
let encode_slice = |valtree: ValTree<'_>| {
83-
let s: Vec<u8> = valtree
84-
.unwrap_branch()
85-
.iter()
86-
.map(|b| u8::try_from(b.unwrap_leaf()).unwrap())
87-
.collect();
88-
let alloc_id = bx.tcx().allocate_bytes(&s);
82+
let encode_slice = |s| {
83+
let alloc_id = bx.tcx().allocate_bytes(s);
8984

9085
let a_scalar = match layout.abi {
9186
Abi::ScalarPair(ref a, _) => a,
@@ -104,8 +99,18 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
10499
let val = match val {
105100
Err(valtree) => match ty.kind() {
106101
ty::Ref(_, pointee, _) => match *pointee.kind() {
107-
ty::Str => encode_slice(valtree),
108-
ty::Slice(elem_ty) if elem_ty == bx.tcx().types.u8 => encode_slice(valtree),
102+
ty::Str => {
103+
let s = valtree.unwrap_str().as_str();
104+
encode_slice(s.as_bytes())
105+
}
106+
ty::Slice(elem_ty) if elem_ty == bx.tcx().types.u8 => {
107+
let s: Vec<u8> = valtree
108+
.unwrap_branch()
109+
.iter()
110+
.map(|b| u8::try_from(b.unwrap_leaf()).unwrap())
111+
.collect();
112+
encode_slice(&s)
113+
}
109114
ty::Array(elem_ty, _) if elem_ty == bx.tcx().types.u8 => {
110115
let s: Vec<u8> = valtree
111116
.unwrap_branch()

compiler/rustc_middle/src/ty/consts/valtree.rs

+14-4
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use crate::ty::TyCtxt;
22

33
use super::ScalarInt;
44
use rustc_macros::HashStable;
5+
use rustc_span::Symbol;
56

67
#[derive(Copy, Clone, Debug, Hash, TyEncodable, TyDecodable, Eq, PartialEq, Ord, PartialOrd)]
78
#[derive(HashStable)]
@@ -30,33 +31,42 @@ pub enum ValTree<'tcx> {
3031
/// Enums are represented by storing their discriminant as a field, followed by all
3132
/// the fields of the variant.
3233
///
33-
/// `&str` and `&[T]` are encoded as if they were `&[T;N]`. So there is no wide pointer
34+
/// `&[T]` are encoded as if they were `&[T;N]`. So there is no wide pointer
3435
/// or metadata encoded, instead the length is taken directly from the number of elements
3536
/// in the branch.
3637
Branch(&'tcx [ValTree<'tcx>]),
38+
/// `&str` could be encoded as a `Branch`, but the back and forth between valtree
39+
/// representations and other representations of `str` is expensive.
40+
Str(Symbol),
3741
}
3842

3943
impl ValTree<'tcx> {
4044
pub fn zst() -> Self {
4145
Self::Branch(&[])
4246
}
47+
pub fn unwrap_str(self) -> Symbol {
48+
match self {
49+
Self::Str(s) => s,
50+
_ => bug!("expected str, got {:?}", self),
51+
}
52+
}
4353
pub fn unwrap_leaf(self) -> ScalarInt {
4454
match self {
4555
Self::Leaf(s) => s,
46-
Self::Branch(branch) => bug!("expected leaf, got {:?}", branch),
56+
_ => bug!("expected leaf, got {:?}", self),
4757
}
4858
}
4959
pub fn unwrap_branch(self) -> &'tcx [Self] {
5060
match self {
51-
Self::Leaf(s) => bug!("expected branch, got {:?}", s),
5261
Self::Branch(branch) => branch,
62+
_ => bug!("expected branch, got {:?}", self),
5363
}
5464
}
5565
#[inline]
5666
pub fn try_to_scalar_int(self) -> Option<ScalarInt> {
5767
match self {
5868
Self::Leaf(s) => Some(s),
59-
Self::Branch(_) => None,
69+
Self::Str(_) | Self::Branch(_) => None,
6070
}
6171
}
6272

compiler/rustc_middle/src/ty/print/pretty.rs

+2-7
Original file line numberDiff line numberDiff line change
@@ -1143,13 +1143,7 @@ pub trait PrettyPrinter<'tcx>:
11431143
match ty.kind() {
11441144
ty::Ref(_, pointee, _) => match *pointee.kind() {
11451145
ty::Str => {
1146-
let s: Vec<u8> = ct
1147-
.unwrap_branch()
1148-
.iter()
1149-
.map(|b| u8::try_from(b.unwrap_leaf()).unwrap())
1150-
.collect();
1151-
let s = String::from_utf8(s).unwrap();
1152-
p!(write("{:?}", s));
1146+
p!(write("{:?}", ct.unwrap_str().as_str()));
11531147
Ok(self)
11541148
}
11551149
// Special case byte strings
@@ -1174,6 +1168,7 @@ pub trait PrettyPrinter<'tcx>:
11741168
_ => match ct {
11751169
ty::ValTree::Leaf(int) => self.pretty_print_const_scalar_int(int, ty, print_ty),
11761170
ty::ValTree::Branch(branches) => bug!("{}: {:?}", ty, branches),
1171+
ty::ValTree::Str(s) => bug!("{}: {}", ty, s),
11771172
},
11781173
}
11791174
}

compiler/rustc_mir/src/const_eval/mod.rs

+17-3
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use rustc_middle::{
1010
ty::{self, Ty, TyCtxt},
1111
};
1212
use rustc_span::{source_map::DUMMY_SP, symbol::Symbol};
13-
use rustc_target::abi::{LayoutOf, VariantIdx};
13+
use rustc_target::abi::{LayoutOf, Size, VariantIdx};
1414

1515
use crate::interpret::{
1616
intern_const_alloc_recursive, ConstValue, InternKind, InterpCx, MPlaceTy, MemPlaceMeta, Scalar,
@@ -123,8 +123,22 @@ fn const_to_valtree<'tcx>(
123123
branches(ecx, n.try_into().unwrap(), None, &mplace)
124124
};
125125
match mplace.layout.ty.kind() {
126-
// str slices are encoded as a `u8` array.
127-
ty::Str => array(ecx.tcx.types.u8),
126+
ty::Str => {
127+
let n = scalar.to_machine_usize(ecx).unwrap();
128+
if n > 0 {
129+
let ptr = mplace.ptr.assert_ptr();
130+
let s = ecx.memory.get_raw(ptr.alloc_id).unwrap().get_bytes(
131+
ecx,
132+
ptr,
133+
Size::from_bytes(n),
134+
).unwrap();
135+
let s = std::str::from_utf8(s).unwrap();
136+
let s = Symbol::intern(s);
137+
Ok(Some(ty::ValTree::Str(s)))
138+
} else {
139+
Ok(Some(ty::ValTree::Str(Symbol::intern(""))))
140+
}
141+
},
128142
// Slices are encoded as an array
129143
ty::Slice(elem_ty) => array(elem_ty),
130144
// No other unsized types are structural match.

compiler/rustc_mir/src/interpret/operand.rs

+5-9
Original file line numberDiff line numberDiff line change
@@ -593,18 +593,14 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
593593
Ok(OpTy { op, layout })
594594
}
595595
ty::Str => {
596-
let bytes: Vec<u8> = val
597-
.unwrap_branch()
598-
.iter()
599-
.map(|vt| u8::try_from(vt.unwrap_leaf()).unwrap())
600-
.collect();
601-
let alloc_id = self.tcx.allocate_bytes(&bytes);
596+
let s = val.unwrap_str().as_str();
597+
let alloc_id = self.tcx.allocate_bytes(s.as_bytes());
602598
let ptr = self.global_base_pointer(alloc_id.into())?;
603599
let layout =
604600
from_known_layout(self.tcx, self.param_env, layout, || self.layout_of(ty))?;
605601
let op = Operand::Immediate(Immediate::new_slice(
606602
ptr.into(),
607-
u64::try_from(bytes.len()).unwrap(),
603+
u64::try_from(s.len()).unwrap(),
608604
self,
609605
));
610606
Ok(OpTy { op, layout })
@@ -620,11 +616,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
620616
ValTree::Leaf(int) => {
621617
self.const_val_to_op(ConstValue::Scalar(int.into()), ty, layout)
622618
}
623-
ValTree::Branch(branches) => span_bug!(
619+
ValTree::Str(_) | ValTree::Branch(_) => span_bug!(
624620
self.cur_span(),
625621
"complex valtrees of type {} are unimplemented: {:?}",
626622
ty,
627-
branches
623+
val
628624
),
629625
},
630626
}

compiler/rustc_mir_build/src/thir/constant.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ crate fn lit_to_const<'tcx>(
2929
};
3030

3131
let val = match (lit, &ty.kind()) {
32-
(ast::LitKind::Str(s, _), ty::Ref(..)) => byte_array(s.as_str().as_bytes()),
32+
(ast::LitKind::Str(s, _), ty::Ref(..)) => ValTree::Str(*s),
3333
(ast::LitKind::ByteStr(data), ty::Ref(..)) => byte_array(data),
3434
(ast::LitKind::Byte(n), ty::Uint(ty::UintTy::U8)) => {
3535
ValTree::Leaf(ScalarInt::from_uint(*n, Size::from_bytes(1)))

src/test/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.32bit.mir

+1-1
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ fn main() -> () {
3939
_5 = foo(move _6) -> bb1; // scope 4 at $DIR/array-index-is-temporary.rs:16:21: 16:27
4040
// mir::Constant
4141
// + span: $DIR/array-index-is-temporary.rs:16:21: 16:24
42-
// + literal: Const { ty: unsafe fn(*mut usize) -> u32 {foo}, val: Value(Scalar(<ZST>)) }
42+
// + literal: Const { ty: unsafe fn(*mut usize) -> u32 {foo}, val: Value(Leaf(<ZST>)) }
4343
}
4444

4545
bb1: {

src/test/mir-opt/const_allocation.main.ConstProp.after.32bit.mir

+1-4
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,9 @@ fn main() -> () {
99
StorageLive(_1); // scope 0 at $DIR/const_allocation.rs:8:5: 8:8
1010
StorageLive(_2); // scope 0 at $DIR/const_allocation.rs:8:5: 8:8
1111
_2 = const {alloc0: &&[(Option<i32>, &[&str])]}; // scope 0 at $DIR/const_allocation.rs:8:5: 8:8
12-
// ty::Const
13-
// + ty: &&[(std::option::Option<i32>, &[&str])]
14-
// + val: Value(Scalar(alloc0))
1512
// mir::Constant
1613
// + span: $DIR/const_allocation.rs:8:5: 8:8
17-
// + literal: Const { ty: &&[(std::option::Option<i32>, &[&str])], val: Value(Scalar(alloc0)) }
14+
// + literal: Const { ty: &&[(Option<i32>, &[&str])], val: Value(Scalar(alloc0)) }
1815
_1 = (*_2); // scope 0 at $DIR/const_allocation.rs:8:5: 8:8
1916
StorageDead(_2); // scope 0 at $DIR/const_allocation.rs:8:8: 8:9
2017
StorageDead(_1); // scope 0 at $DIR/const_allocation.rs:8:8: 8:9

src/test/mir-opt/const_allocation2.main.ConstProp.after.32bit.mir

+1-4
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,9 @@ fn main() -> () {
99
StorageLive(_1); // scope 0 at $DIR/const_allocation2.rs:5:5: 5:8
1010
StorageLive(_2); // scope 0 at $DIR/const_allocation2.rs:5:5: 5:8
1111
_2 = const {alloc0: &&[(Option<i32>, &[&u8])]}; // scope 0 at $DIR/const_allocation2.rs:5:5: 5:8
12-
// ty::Const
13-
// + ty: &&[(std::option::Option<i32>, &[&u8])]
14-
// + val: Value(Scalar(alloc0))
1512
// mir::Constant
1613
// + span: $DIR/const_allocation2.rs:5:5: 5:8
17-
// + literal: Const { ty: &&[(std::option::Option<i32>, &[&u8])], val: Value(Scalar(alloc0)) }
14+
// + literal: Const { ty: &&[(Option<i32>, &[&u8])], val: Value(Scalar(alloc0)) }
1815
_1 = (*_2); // scope 0 at $DIR/const_allocation2.rs:5:5: 5:8
1916
StorageDead(_2); // scope 0 at $DIR/const_allocation2.rs:5:8: 5:9
2017
StorageDead(_1); // scope 0 at $DIR/const_allocation2.rs:5:8: 5:9

src/test/mir-opt/const_allocation3.main.ConstProp.after.32bit.mir

-3
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,6 @@ fn main() -> () {
99
StorageLive(_1); // scope 0 at $DIR/const_allocation3.rs:5:5: 5:8
1010
StorageLive(_2); // scope 0 at $DIR/const_allocation3.rs:5:5: 5:8
1111
_2 = const {alloc0: &&Packed}; // scope 0 at $DIR/const_allocation3.rs:5:5: 5:8
12-
// ty::Const
13-
// + ty: &&Packed
14-
// + val: Value(Scalar(alloc0))
1512
// mir::Constant
1613
// + span: $DIR/const_allocation3.rs:5:5: 5:8
1714
// + literal: Const { ty: &&Packed, val: Value(Scalar(alloc0)) }

src/test/mir-opt/const_debuginfo.main.ConstDebugInfo.diff

+2-2
Original file line numberDiff line numberDiff line change
@@ -77,10 +77,10 @@
7777
_9 = const "hello, world!"; // scope 4 at $DIR/const_debuginfo.rs:14:13: 14:28
7878
// ty::Const
7979
// + ty: &str
80-
// + val: Value(Branch([Leaf(0x68), Leaf(0x65), Leaf(0x6c), Leaf(0x6c), Leaf(0x6f), Leaf(0x2c), Leaf(0x20), Leaf(0x77), Leaf(0x6f), Leaf(0x72), Leaf(0x6c), Leaf(0x64), Leaf(0x21)]))
80+
// + val: Value(Str("hello, world!"))
8181
// mir::Constant
8282
// + span: $DIR/const_debuginfo.rs:14:13: 14:28
83-
// + literal: Const { ty: &str, val: Value(Branch([Leaf(0x68), Leaf(0x65), Leaf(0x6c), Leaf(0x6c), Leaf(0x6f), Leaf(0x2c), Leaf(0x20), Leaf(0x77), Leaf(0x6f), Leaf(0x72), Leaf(0x6c), Leaf(0x64), Leaf(0x21)])) }
83+
// + literal: Const { ty: &str, val: Value(Str("hello, world!")) }
8484
StorageLive(_10); // scope 5 at $DIR/const_debuginfo.rs:16:9: 16:10
8585
(_10.0: bool) = const true; // scope 5 at $DIR/const_debuginfo.rs:16:13: 16:34
8686
(_10.1: bool) = const false; // scope 5 at $DIR/const_debuginfo.rs:16:13: 16:34

src/test/mir-opt/const_prop/control_flow_simplification.hello.ConstProp.diff

+2-2
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,10 @@
2222
// + literal: Const { ty: fn(&str) -> ! {std::rt::begin_panic::<&str>}, val: Value(Leaf(<ZST>)) }
2323
// ty::Const
2424
// + ty: &str
25-
// + val: Value(Branch([Leaf(0x65), Leaf(0x78), Leaf(0x70), Leaf(0x6c), Leaf(0x69), Leaf(0x63), Leaf(0x69), Leaf(0x74), Leaf(0x20), Leaf(0x70), Leaf(0x61), Leaf(0x6e), Leaf(0x69), Leaf(0x63)]))
25+
// + val: Value(Str("explicit panic"))
2626
// mir::Constant
2727
// + span: $SRC_DIR/std/src/panic.rs:LL:COL
28-
// + literal: Const { ty: &str, val: Value(Branch([Leaf(0x65), Leaf(0x78), Leaf(0x70), Leaf(0x6c), Leaf(0x69), Leaf(0x63), Leaf(0x69), Leaf(0x74), Leaf(0x20), Leaf(0x70), Leaf(0x61), Leaf(0x6e), Leaf(0x69), Leaf(0x63)])) }
28+
// + literal: Const { ty: &str, val: Value(Str("explicit panic")) }
2929
}
3030

3131
bb2: {

src/test/mir-opt/inline/inline_diverging.g.Inline.diff

+2-2
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,10 @@
4343
+ // + literal: Const { ty: fn(&str) -> ! {std::rt::begin_panic::<&str>}, val: Value(Leaf(<ZST>)) }
4444
+ // ty::Const
4545
+ // + ty: &str
46-
+ // + val: Value(Branch([Leaf(0x65), Leaf(0x78), Leaf(0x70), Leaf(0x6c), Leaf(0x69), Leaf(0x63), Leaf(0x69), Leaf(0x74), Leaf(0x20), Leaf(0x70), Leaf(0x61), Leaf(0x6e), Leaf(0x69), Leaf(0x63)]))
46+
+ // + val: Value(Str("explicit panic"))
4747
+ // mir::Constant
4848
+ // + span: $DIR/inline-diverging.rs:16:9: 16:16
49-
+ // + literal: Const { ty: &str, val: Value(Branch([Leaf(0x65), Leaf(0x78), Leaf(0x70), Leaf(0x6c), Leaf(0x69), Leaf(0x63), Leaf(0x69), Leaf(0x74), Leaf(0x20), Leaf(0x70), Leaf(0x61), Leaf(0x6e), Leaf(0x69), Leaf(0x63)])) }
49+
+ // + literal: Const { ty: &str, val: Value(Str("explicit panic")) }
5050
}
5151
}
5252

src/test/mir-opt/inline/inline_into_box_place.main.Inline.32bit.diff

+2-2
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
// mir::Constant
2525
- // + span: $DIR/inline-into-box-place.rs:8:33: 8:41
2626
- // + user_ty: UserType(1)
27-
- // + literal: Const { ty: fn() -> std::vec::Vec<u32> {std::vec::Vec::<u32>::new}, val: Value(Scalar(<ZST>)) }
27+
- // + literal: Const { ty: fn() -> std::vec::Vec<u32> {std::vec::Vec::<u32>::new}, val: Value(Leaf(<ZST>)) }
2828
- }
2929
-
3030
- bb1: {
@@ -55,7 +55,7 @@
5555
- _3 = alloc::alloc::box_free::<Vec<u32>, std::alloc::Global>(move (_2.0: std::ptr::Unique<std::vec::Vec<u32>>), move (_2.1: std::alloc::Global)) -> bb3; // scope 0 at $DIR/inline-into-box-place.rs:8:42: 8:43
5656
- // mir::Constant
5757
- // + span: $DIR/inline-into-box-place.rs:8:42: 8:43
58-
- // + literal: Const { ty: unsafe fn(std::ptr::Unique<std::vec::Vec<u32>>, std::alloc::Global) {alloc::alloc::box_free::<std::vec::Vec<u32>, std::alloc::Global>}, val: Value(Scalar(<ZST>)) }
58+
- // + literal: Const { ty: unsafe fn(std::ptr::Unique<std::vec::Vec<u32>>, std::alloc::Global) {alloc::alloc::box_free::<std::vec::Vec<u32>, std::alloc::Global>}, val: Value(Leaf(<ZST>)) }
5959
}
6060
}
6161

src/test/mir-opt/instrument_coverage.main.InstrumentCoverage.diff

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
_2 = bar() -> [return: bb2, unwind: bb5]; // scope 0 at /the/src/instrument_coverage.rs:12:12: 12:17
1818
// mir::Constant
1919
// + span: /the/src/instrument_coverage.rs:12:12: 12:15
20-
// + literal: Const { ty: fn() -> bool {bar}, val: Value(Scalar(<ZST>)) }
20+
// + literal: Const { ty: fn() -> bool {bar}, val: Value(Leaf(<ZST>)) }
2121
}
2222

2323
bb2: {

src/test/mir-opt/issue_72181.main.mir_map.0.32bit.mir

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ fn main() -> () {
2525
_1 = std::mem::size_of::<Foo>() -> [return: bb1, unwind: bb3]; // scope 0 at $DIR/issue-72181.rs:24:13: 24:34
2626
// mir::Constant
2727
// + span: $DIR/issue-72181.rs:24:13: 24:32
28-
// + literal: Const { ty: fn() -> usize {std::mem::size_of::<Foo>}, val: Value(Scalar(<ZST>)) }
28+
// + literal: Const { ty: fn() -> usize {std::mem::size_of::<Foo>}, val: Value(Leaf(<ZST>)) }
2929
}
3030

3131
bb1: {

0 commit comments

Comments
 (0)