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 #28912.
This commit is contained in:
parent
7ff4524e54
commit
6ad079e341
@ -98,7 +98,7 @@ pub fn const_lit(cx: &CrateContext, e: &hir::Expr, lit: &ast::Lit)
|
|||||||
ast::LitBool(b) => C_bool(cx, b),
|
ast::LitBool(b) => C_bool(cx, b),
|
||||||
ast::LitStr(ref s, _) => C_str_slice(cx, (*s).clone()),
|
ast::LitStr(ref s, _) => C_str_slice(cx, (*s).clone()),
|
||||||
ast::LitByteStr(ref data) => {
|
ast::LitByteStr(ref data) => {
|
||||||
addr_of(cx, C_bytes(cx, &data[..]), "byte_str")
|
addr_of(cx, C_bytes(cx, &data[..]), 1, "byte_str")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -111,6 +111,7 @@ pub fn ptrcast(val: ValueRef, ty: Type) -> ValueRef {
|
|||||||
|
|
||||||
fn addr_of_mut(ccx: &CrateContext,
|
fn addr_of_mut(ccx: &CrateContext,
|
||||||
cv: ValueRef,
|
cv: ValueRef,
|
||||||
|
align: machine::llalign,
|
||||||
kind: &str)
|
kind: &str)
|
||||||
-> ValueRef {
|
-> ValueRef {
|
||||||
unsafe {
|
unsafe {
|
||||||
@ -122,6 +123,7 @@ fn addr_of_mut(ccx: &CrateContext,
|
|||||||
ccx.sess().bug(&format!("symbol `{}` is already defined", name));
|
ccx.sess().bug(&format!("symbol `{}` is already defined", name));
|
||||||
});
|
});
|
||||||
llvm::LLVMSetInitializer(gv, cv);
|
llvm::LLVMSetInitializer(gv, cv);
|
||||||
|
llvm::LLVMSetAlignment(gv, align);
|
||||||
SetLinkage(gv, InternalLinkage);
|
SetLinkage(gv, InternalLinkage);
|
||||||
SetUnnamedAddr(gv, true);
|
SetUnnamedAddr(gv, true);
|
||||||
gv
|
gv
|
||||||
@ -130,13 +132,23 @@ fn addr_of_mut(ccx: &CrateContext,
|
|||||||
|
|
||||||
pub fn addr_of(ccx: &CrateContext,
|
pub fn addr_of(ccx: &CrateContext,
|
||||||
cv: ValueRef,
|
cv: ValueRef,
|
||||||
|
align: machine::llalign,
|
||||||
kind: &str)
|
kind: &str)
|
||||||
-> ValueRef {
|
-> ValueRef {
|
||||||
match ccx.const_globals().borrow().get(&cv) {
|
match ccx.const_globals().borrow().get(&cv) {
|
||||||
Some(&gv) => return gv,
|
Some(&gv) => {
|
||||||
|
unsafe {
|
||||||
|
// Upgrade the alignment in cases where the same constant is used with different
|
||||||
|
// alignment requirements
|
||||||
|
if align > llvm::LLVMGetAlignment(gv) {
|
||||||
|
llvm::LLVMSetAlignment(gv, align);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return gv;
|
||||||
|
}
|
||||||
None => {}
|
None => {}
|
||||||
}
|
}
|
||||||
let gv = addr_of_mut(ccx, cv, kind);
|
let gv = addr_of_mut(ccx, cv, align, kind);
|
||||||
unsafe {
|
unsafe {
|
||||||
llvm::LLVMSetGlobalConstant(gv, True);
|
llvm::LLVMSetGlobalConstant(gv, True);
|
||||||
}
|
}
|
||||||
@ -254,11 +266,11 @@ pub fn get_const_expr_as_global<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
|||||||
Some(&val) => return val,
|
Some(&val) => return val,
|
||||||
None => {}
|
None => {}
|
||||||
}
|
}
|
||||||
|
let ty = monomorphize::apply_param_substs(ccx.tcx(), param_substs,
|
||||||
|
&ccx.tcx().expr_ty(expr));
|
||||||
let val = if qualif.intersects(check_const::ConstQualif::NON_STATIC_BORROWS) {
|
let val = if qualif.intersects(check_const::ConstQualif::NON_STATIC_BORROWS) {
|
||||||
// Avoid autorefs as they would create global instead of stack
|
// Avoid autorefs as they would create global instead of stack
|
||||||
// references, even when only the latter are correct.
|
// references, even when only the latter are correct.
|
||||||
let ty = monomorphize::apply_param_substs(ccx.tcx(), param_substs,
|
|
||||||
&ccx.tcx().expr_ty(expr));
|
|
||||||
const_expr_unadjusted(ccx, expr, ty, param_substs, None)
|
const_expr_unadjusted(ccx, expr, ty, param_substs, None)
|
||||||
} else {
|
} else {
|
||||||
const_expr(ccx, expr, param_substs, None).0
|
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>,
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let lvalue = addr_of(ccx, val, "const");
|
let lvalue = addr_of(ccx, val, type_of::align_of(ccx, ty), "const");
|
||||||
ccx.const_values().borrow_mut().insert(key, lvalue);
|
ccx.const_values().borrow_mut().insert(key, lvalue);
|
||||||
lvalue
|
lvalue
|
||||||
}
|
}
|
||||||
@ -314,7 +326,7 @@ pub fn const_expr<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
|||||||
if adj.autoderefs == 0 {
|
if adj.autoderefs == 0 {
|
||||||
// Don't copy data to do a deref+ref
|
// Don't copy data to do a deref+ref
|
||||||
// (i.e., skip the last auto-deref).
|
// (i.e., skip the last auto-deref).
|
||||||
llconst = addr_of(cx, llconst, "autoref");
|
llconst = addr_of(cx, llconst, type_of::align_of(cx, ty), "autoref");
|
||||||
ty = cx.tcx().mk_imm_ref(cx.tcx().mk_region(ty::ReStatic), ty);
|
ty = cx.tcx().mk_imm_ref(cx.tcx().mk_region(ty::ReStatic), ty);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -720,13 +732,13 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
|||||||
} else {
|
} else {
|
||||||
// If this isn't the address of a static, then keep going through
|
// If this isn't the address of a static, then keep going through
|
||||||
// normal constant evaluation.
|
// normal constant evaluation.
|
||||||
let (v, _) = const_expr(cx, &**sub, param_substs, fn_args);
|
let (v, ty) = const_expr(cx, &**sub, param_substs, fn_args);
|
||||||
addr_of(cx, v, "ref")
|
addr_of(cx, v, type_of::align_of(cx, ty), "ref")
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
hir::ExprAddrOf(hir::MutMutable, ref sub) => {
|
hir::ExprAddrOf(hir::MutMutable, ref sub) => {
|
||||||
let (v, _) = const_expr(cx, &**sub, param_substs, fn_args);
|
let (v, ty) = const_expr(cx, &**sub, param_substs, fn_args);
|
||||||
addr_of_mut(cx, v, "ref_mut_slice")
|
addr_of_mut(cx, v, type_of::align_of(cx, ty), "ref_mut_slice")
|
||||||
},
|
},
|
||||||
hir::ExprTup(ref es) => {
|
hir::ExprTup(ref es) => {
|
||||||
let repr = adt::represent_type(cx, ety);
|
let repr = adt::represent_type(cx, ety);
|
||||||
@ -934,6 +946,7 @@ pub fn trans_static(ccx: &CrateContext,
|
|||||||
ccx.statics_to_rauw().borrow_mut().push((g, new_g));
|
ccx.statics_to_rauw().borrow_mut().push((g, new_g));
|
||||||
new_g
|
new_g
|
||||||
};
|
};
|
||||||
|
llvm::LLVMSetAlignment(g, type_of::align_of(ccx, ty));
|
||||||
llvm::LLVMSetInitializer(g, v);
|
llvm::LLVMSetInitializer(g, v);
|
||||||
|
|
||||||
// As an optimization, all shared statics which do not have interior
|
// As an optimization, all shared statics which do not have interior
|
||||||
|
@ -22,6 +22,7 @@ use trans::consts;
|
|||||||
use trans::debuginfo;
|
use trans::debuginfo;
|
||||||
use trans::debuginfo::{DebugLoc, ToDebugLoc};
|
use trans::debuginfo::{DebugLoc, ToDebugLoc};
|
||||||
use trans::expr;
|
use trans::expr;
|
||||||
|
use trans::machine;
|
||||||
use trans;
|
use trans;
|
||||||
use middle::ty;
|
use middle::ty;
|
||||||
|
|
||||||
@ -401,7 +402,8 @@ pub fn trans_fail<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|||||||
let filename = C_str_slice(ccx, filename);
|
let filename = C_str_slice(ccx, filename);
|
||||||
let line = C_u32(ccx, loc.line as u32);
|
let line = C_u32(ccx, loc.line as u32);
|
||||||
let expr_file_line_const = C_struct(ccx, &[v_str, filename, line], false);
|
let expr_file_line_const = C_struct(ccx, &[v_str, filename, line], false);
|
||||||
let expr_file_line = consts::addr_of(ccx, expr_file_line_const, "panic_loc");
|
let align = machine::llalign_of_min(ccx, val_ty(expr_file_line_const));
|
||||||
|
let expr_file_line = consts::addr_of(ccx, expr_file_line_const, align, "panic_loc");
|
||||||
let args = vec!(expr_file_line);
|
let args = vec!(expr_file_line);
|
||||||
let did = langcall(bcx, Some(call_info.span), "", PanicFnLangItem);
|
let did = langcall(bcx, Some(call_info.span), "", PanicFnLangItem);
|
||||||
let bcx = callee::trans_lang_call(bcx,
|
let bcx = callee::trans_lang_call(bcx,
|
||||||
@ -433,7 +435,8 @@ pub fn trans_fail_bounds_check<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|||||||
let filename = C_str_slice(ccx, filename);
|
let filename = C_str_slice(ccx, filename);
|
||||||
let line = C_u32(ccx, loc.line as u32);
|
let line = C_u32(ccx, loc.line as u32);
|
||||||
let file_line_const = C_struct(ccx, &[filename, line], false);
|
let file_line_const = C_struct(ccx, &[filename, line], false);
|
||||||
let file_line = consts::addr_of(ccx, file_line_const, "panic_bounds_check_loc");
|
let align = machine::llalign_of_min(ccx, val_ty(file_line_const));
|
||||||
|
let file_line = consts::addr_of(ccx, file_line_const, align, "panic_bounds_check_loc");
|
||||||
let args = vec!(file_line, index, len);
|
let args = vec!(file_line, index, len);
|
||||||
let did = langcall(bcx, Some(call_info.span), "", PanicBoundsCheckFnLangItem);
|
let did = langcall(bcx, Some(call_info.span), "", PanicBoundsCheckFnLangItem);
|
||||||
let bcx = callee::trans_lang_call(bcx,
|
let bcx = callee::trans_lang_call(bcx,
|
||||||
|
@ -651,7 +651,9 @@ pub fn get_vtable<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
|||||||
C_uint(ccx, align)
|
C_uint(ccx, align)
|
||||||
].into_iter().chain(methods).collect();
|
].into_iter().chain(methods).collect();
|
||||||
|
|
||||||
let vtable = consts::addr_of(ccx, C_struct(ccx, &components, false), "vtable");
|
let vtable_const = C_struct(ccx, &components, false);
|
||||||
|
let align = machine::llalign_of_pref(ccx, val_ty(vtable_const));
|
||||||
|
let vtable = consts::addr_of(ccx, vtable_const, align, "vtable");
|
||||||
|
|
||||||
ccx.vtables().borrow_mut().insert(trait_ref, vtable);
|
ccx.vtables().borrow_mut().insert(trait_ref, vtable);
|
||||||
vtable
|
vtable
|
||||||
|
66
src/test/codegen/consts.rs
Normal file
66
src/test/codegen/consts.rs
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
// compile-flags: -C no-prepopulate-passes
|
||||||
|
|
||||||
|
#![crate_type = "lib"]
|
||||||
|
|
||||||
|
// Below, these constants are defined as enum variants that by itself would
|
||||||
|
// have a lower alignment than the enum type. Ensure that we mark them
|
||||||
|
// correctly with the higher alignment of the enum.
|
||||||
|
|
||||||
|
// CHECK: @STATIC = {{.*}}, align 4
|
||||||
|
|
||||||
|
// This checks the constants from inline_enum_const
|
||||||
|
// CHECK: @const{{[0-9]+}} = {{.*}}, align 2
|
||||||
|
|
||||||
|
// This checks the constants from {low,high}_align_const, they share the same
|
||||||
|
// constant, but the alignment differs, so the higher one should be used
|
||||||
|
// CHECK: @const{{[0-9]+}} = {{.*}}, align 4
|
||||||
|
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
|
||||||
|
// repr(i16) is required for the {low,high}_align_const test
|
||||||
|
#[repr(i16)]
|
||||||
|
pub enum E<A, B> {
|
||||||
|
A(A),
|
||||||
|
B(B),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub static STATIC: E<i16, i32> = E::A(0);
|
||||||
|
|
||||||
|
// CHECK-LABEL: @static_enum_const
|
||||||
|
#[no_mangle]
|
||||||
|
pub fn static_enum_const() -> E<i16, i32> {
|
||||||
|
STATIC
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK-LABEL: @inline_enum_const
|
||||||
|
#[no_mangle]
|
||||||
|
pub fn inline_enum_const() -> E<i8, i16> {
|
||||||
|
E::A(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK-LABEL: @low_align_const
|
||||||
|
#[no_mangle]
|
||||||
|
pub fn low_align_const() -> E<i16, [i16; 3]> {
|
||||||
|
// Check that low_align_const and high_align_const use the same constant
|
||||||
|
// CHECK: call void @llvm.memcpy.{{.*}}(i8* %{{[0-9]+}}, i8* {{.*}} [[LOW_HIGH:@const[0-9]+]]
|
||||||
|
E::A(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK-LABEL: @high_align_const
|
||||||
|
#[no_mangle]
|
||||||
|
pub fn high_align_const() -> E<i16, i32> {
|
||||||
|
// Check that low_align_const and high_align_const use the same constant
|
||||||
|
// CHECK: call void @llvm.memcpy.{{.*}}(i8* %{{[0-9]}}, i8* {{.*}} [[LOW_HIGH]]
|
||||||
|
E::A(0)
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user