Skip to content

Commit 39376de

Browse files
committed
Auto merge of #28920 - dotdash:const_align, r=eddyb
For enum variants, the default alignment for a specific variant might be lower than the alignment of the enum type itself. In such cases we, for example, generate memcpy calls with an alignment that's higher than the alignment of the constant we copy from. To avoid that, we need to explicitly set the required alignment on constants. Fixes #28912.
2 parents 840d29e + 6ad079e commit 39376de

File tree

5 files changed

+101
-16
lines changed

5 files changed

+101
-16
lines changed

src/librustc_trans/trans/consts.rs

+24-11
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ pub fn const_lit(cx: &CrateContext, e: &hir::Expr, lit: &ast::Lit)
9898
ast::LitBool(b) => C_bool(cx, b),
9999
ast::LitStr(ref s, _) => C_str_slice(cx, (*s).clone()),
100100
ast::LitByteStr(ref data) => {
101-
addr_of(cx, C_bytes(cx, &data[..]), "byte_str")
101+
addr_of(cx, C_bytes(cx, &data[..]), 1, "byte_str")
102102
}
103103
}
104104
}
@@ -111,6 +111,7 @@ pub fn ptrcast(val: ValueRef, ty: Type) -> ValueRef {
111111

112112
fn addr_of_mut(ccx: &CrateContext,
113113
cv: ValueRef,
114+
align: machine::llalign,
114115
kind: &str)
115116
-> ValueRef {
116117
unsafe {
@@ -122,6 +123,7 @@ fn addr_of_mut(ccx: &CrateContext,
122123
ccx.sess().bug(&format!("symbol `{}` is already defined", name));
123124
});
124125
llvm::LLVMSetInitializer(gv, cv);
126+
llvm::LLVMSetAlignment(gv, align);
125127
SetLinkage(gv, InternalLinkage);
126128
SetUnnamedAddr(gv, true);
127129
gv
@@ -130,13 +132,23 @@ fn addr_of_mut(ccx: &CrateContext,
130132

131133
pub fn addr_of(ccx: &CrateContext,
132134
cv: ValueRef,
135+
align: machine::llalign,
133136
kind: &str)
134137
-> ValueRef {
135138
match ccx.const_globals().borrow().get(&cv) {
136-
Some(&gv) => return gv,
139+
Some(&gv) => {
140+
unsafe {
141+
// Upgrade the alignment in cases where the same constant is used with different
142+
// alignment requirements
143+
if align > llvm::LLVMGetAlignment(gv) {
144+
llvm::LLVMSetAlignment(gv, align);
145+
}
146+
}
147+
return gv;
148+
}
137149
None => {}
138150
}
139-
let gv = addr_of_mut(ccx, cv, kind);
151+
let gv = addr_of_mut(ccx, cv, align, kind);
140152
unsafe {
141153
llvm::LLVMSetGlobalConstant(gv, True);
142154
}
@@ -254,11 +266,11 @@ pub fn get_const_expr_as_global<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
254266
Some(&val) => return val,
255267
None => {}
256268
}
269+
let ty = monomorphize::apply_param_substs(ccx.tcx(), param_substs,
270+
&ccx.tcx().expr_ty(expr));
257271
let val = if qualif.intersects(check_const::ConstQualif::NON_STATIC_BORROWS) {
258272
// Avoid autorefs as they would create global instead of stack
259273
// references, even when only the latter are correct.
260-
let ty = monomorphize::apply_param_substs(ccx.tcx(), param_substs,
261-
&ccx.tcx().expr_ty(expr));
262274
const_expr_unadjusted(ccx, expr, ty, param_substs, None)
263275
} else {
264276
const_expr(ccx, expr, param_substs, None).0
@@ -274,7 +286,7 @@ pub fn get_const_expr_as_global<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
274286
}
275287
};
276288

277-
let lvalue = addr_of(ccx, val, "const");
289+
let lvalue = addr_of(ccx, val, type_of::align_of(ccx, ty), "const");
278290
ccx.const_values().borrow_mut().insert(key, lvalue);
279291
lvalue
280292
}
@@ -314,7 +326,7 @@ pub fn const_expr<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
314326
if adj.autoderefs == 0 {
315327
// Don't copy data to do a deref+ref
316328
// (i.e., skip the last auto-deref).
317-
llconst = addr_of(cx, llconst, "autoref");
329+
llconst = addr_of(cx, llconst, type_of::align_of(cx, ty), "autoref");
318330
ty = cx.tcx().mk_imm_ref(cx.tcx().mk_region(ty::ReStatic), ty);
319331
}
320332
} else {
@@ -720,13 +732,13 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
720732
} else {
721733
// If this isn't the address of a static, then keep going through
722734
// normal constant evaluation.
723-
let (v, _) = const_expr(cx, &**sub, param_substs, fn_args);
724-
addr_of(cx, v, "ref")
735+
let (v, ty) = const_expr(cx, &**sub, param_substs, fn_args);
736+
addr_of(cx, v, type_of::align_of(cx, ty), "ref")
725737
}
726738
},
727739
hir::ExprAddrOf(hir::MutMutable, ref sub) => {
728-
let (v, _) = const_expr(cx, &**sub, param_substs, fn_args);
729-
addr_of_mut(cx, v, "ref_mut_slice")
740+
let (v, ty) = const_expr(cx, &**sub, param_substs, fn_args);
741+
addr_of_mut(cx, v, type_of::align_of(cx, ty), "ref_mut_slice")
730742
},
731743
hir::ExprTup(ref es) => {
732744
let repr = adt::represent_type(cx, ety);
@@ -934,6 +946,7 @@ pub fn trans_static(ccx: &CrateContext,
934946
ccx.statics_to_rauw().borrow_mut().push((g, new_g));
935947
new_g
936948
};
949+
llvm::LLVMSetAlignment(g, type_of::align_of(ccx, ty));
937950
llvm::LLVMSetInitializer(g, v);
938951

939952
// As an optimization, all shared statics which do not have interior

src/librustc_trans/trans/controlflow.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ use trans::consts;
2222
use trans::debuginfo;
2323
use trans::debuginfo::{DebugLoc, ToDebugLoc};
2424
use trans::expr;
25+
use trans::machine;
2526
use trans;
2627
use middle::ty;
2728

@@ -401,7 +402,8 @@ pub fn trans_fail<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
401402
let filename = C_str_slice(ccx, filename);
402403
let line = C_u32(ccx, loc.line as u32);
403404
let expr_file_line_const = C_struct(ccx, &[v_str, filename, line], false);
404-
let expr_file_line = consts::addr_of(ccx, expr_file_line_const, "panic_loc");
405+
let align = machine::llalign_of_min(ccx, val_ty(expr_file_line_const));
406+
let expr_file_line = consts::addr_of(ccx, expr_file_line_const, align, "panic_loc");
405407
let args = vec!(expr_file_line);
406408
let did = langcall(bcx, Some(call_info.span), "", PanicFnLangItem);
407409
let bcx = callee::trans_lang_call(bcx,
@@ -433,7 +435,8 @@ pub fn trans_fail_bounds_check<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
433435
let filename = C_str_slice(ccx, filename);
434436
let line = C_u32(ccx, loc.line as u32);
435437
let file_line_const = C_struct(ccx, &[filename, line], false);
436-
let file_line = consts::addr_of(ccx, file_line_const, "panic_bounds_check_loc");
438+
let align = machine::llalign_of_min(ccx, val_ty(file_line_const));
439+
let file_line = consts::addr_of(ccx, file_line_const, align, "panic_bounds_check_loc");
437440
let args = vec!(file_line, index, len);
438441
let did = langcall(bcx, Some(call_info.span), "", PanicBoundsCheckFnLangItem);
439442
let bcx = callee::trans_lang_call(bcx,

src/librustc_trans/trans/debuginfo/gdb.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -54,11 +54,12 @@ pub fn insert_reference_to_gdb_debug_scripts_section_global(ccx: &CrateContext)
5454
/// section.
5555
pub fn get_or_insert_gdb_debug_scripts_section_global(ccx: &CrateContext)
5656
-> llvm::ValueRef {
57-
let section_var_name = "__rustc_debug_gdb_scripts_section__";
57+
let c_section_var_name = "__rustc_debug_gdb_scripts_section__\0";
58+
let section_var_name = &c_section_var_name[..c_section_var_name.len()-1];
5859

5960
let section_var = unsafe {
6061
llvm::LLVMGetNamedGlobal(ccx.llmod(),
61-
section_var_name.as_ptr() as *const _)
62+
c_section_var_name.as_ptr() as *const _)
6263
};
6364

6465
if section_var == ptr::null_mut() {

src/librustc_trans/trans/meth.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -650,7 +650,9 @@ pub fn get_vtable<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
650650
C_uint(ccx, align)
651651
].into_iter().chain(methods).collect();
652652

653-
let vtable = consts::addr_of(ccx, C_struct(ccx, &components, false), "vtable");
653+
let vtable_const = C_struct(ccx, &components, false);
654+
let align = machine::llalign_of_pref(ccx, val_ty(vtable_const));
655+
let vtable = consts::addr_of(ccx, vtable_const, align, "vtable");
654656

655657
ccx.vtables().borrow_mut().insert(trait_ref, vtable);
656658
vtable

src/test/codegen/consts.rs

+66
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// compile-flags: -C no-prepopulate-passes
12+
13+
#![crate_type = "lib"]
14+
15+
// Below, these constants are defined as enum variants that by itself would
16+
// have a lower alignment than the enum type. Ensure that we mark them
17+
// correctly with the higher alignment of the enum.
18+
19+
// CHECK: @STATIC = {{.*}}, align 4
20+
21+
// This checks the constants from inline_enum_const
22+
// CHECK: @const{{[0-9]+}} = {{.*}}, align 2
23+
24+
// This checks the constants from {low,high}_align_const, they share the same
25+
// constant, but the alignment differs, so the higher one should be used
26+
// CHECK: @const{{[0-9]+}} = {{.*}}, align 4
27+
28+
#[derive(Copy, Clone)]
29+
30+
// repr(i16) is required for the {low,high}_align_const test
31+
#[repr(i16)]
32+
pub enum E<A, B> {
33+
A(A),
34+
B(B),
35+
}
36+
37+
#[no_mangle]
38+
pub static STATIC: E<i16, i32> = E::A(0);
39+
40+
// CHECK-LABEL: @static_enum_const
41+
#[no_mangle]
42+
pub fn static_enum_const() -> E<i16, i32> {
43+
STATIC
44+
}
45+
46+
// CHECK-LABEL: @inline_enum_const
47+
#[no_mangle]
48+
pub fn inline_enum_const() -> E<i8, i16> {
49+
E::A(0)
50+
}
51+
52+
// CHECK-LABEL: @low_align_const
53+
#[no_mangle]
54+
pub fn low_align_const() -> E<i16, [i16; 3]> {
55+
// Check that low_align_const and high_align_const use the same constant
56+
// CHECK: call void @llvm.memcpy.{{.*}}(i8* %{{[0-9]+}}, i8* {{.*}} [[LOW_HIGH:@const[0-9]+]]
57+
E::A(0)
58+
}
59+
60+
// CHECK-LABEL: @high_align_const
61+
#[no_mangle]
62+
pub fn high_align_const() -> E<i16, i32> {
63+
// Check that low_align_const and high_align_const use the same constant
64+
// CHECK: call void @llvm.memcpy.{{.*}}(i8* %{{[0-9]}}, i8* {{.*}} [[LOW_HIGH]]
65+
E::A(0)
66+
}

0 commit comments

Comments
 (0)