Skip to content

Commit 6ad079e

Browse files
committed
Set proper alignment on constants
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 rust-lang#28912.
1 parent 7ff4524 commit 6ad079e

File tree

4 files changed

+98
-14
lines changed

4 files changed

+98
-14
lines changed

src/librustc_trans/trans/consts.rs

Lines changed: 24 additions & 11 deletions
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

Lines changed: 5 additions & 2 deletions
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/meth.rs

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

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

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

src/test/codegen/consts.rs

Lines changed: 66 additions & 0 deletions
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)