2012-12-03 18:48:01 -06:00
|
|
|
// Copyright 2012 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.
|
|
|
|
|
2013-01-08 21:37:25 -06:00
|
|
|
use core::prelude::*;
|
2013-01-07 16:16:52 -06:00
|
|
|
|
2013-03-07 14:34:58 -06:00
|
|
|
use back::abi;
|
2013-03-31 21:27:51 -05:00
|
|
|
use lib::llvm::{llvm, SetLinkage, PrivateLinkage,
|
2013-03-28 20:15:35 -05:00
|
|
|
ValueRef, TypeRef, Bool, True, False};
|
2013-03-07 00:30:20 -06:00
|
|
|
use metadata::csearch;
|
2012-12-23 16:41:37 -06:00
|
|
|
use middle::const_eval;
|
2013-02-24 16:38:59 -06:00
|
|
|
use middle::trans::adt;
|
2013-02-25 13:11:21 -06:00
|
|
|
use middle::trans::base;
|
2012-12-13 15:05:22 -06:00
|
|
|
use middle::trans::base::get_insn_ctxt;
|
|
|
|
use middle::trans::common::*;
|
2012-12-23 16:41:37 -06:00
|
|
|
use middle::trans::consts;
|
|
|
|
use middle::trans::expr;
|
2013-03-07 00:30:20 -06:00
|
|
|
use middle::trans::inline;
|
2013-01-30 13:46:19 -06:00
|
|
|
use middle::trans::machine;
|
2013-02-25 13:11:21 -06:00
|
|
|
use middle::trans::type_of;
|
2012-12-23 16:41:37 -06:00
|
|
|
use middle::ty;
|
2013-03-03 16:30:06 -06:00
|
|
|
use util::ppaux::{expr_repr, ty_to_str};
|
2012-12-13 15:05:22 -06:00
|
|
|
|
2013-02-25 13:11:21 -06:00
|
|
|
use core::libc::c_uint;
|
2013-03-26 15:38:07 -05:00
|
|
|
use syntax::{ast, ast_util, ast_map};
|
2013-03-20 14:55:18 -05:00
|
|
|
use util::ppaux::ty_to_str;
|
2012-07-31 20:34:36 -05:00
|
|
|
|
2013-02-19 01:40:42 -06:00
|
|
|
pub fn const_lit(cx: @CrateContext, e: @ast::expr, lit: ast::lit)
|
2012-07-31 20:34:36 -05:00
|
|
|
-> ValueRef {
|
2012-08-14 18:45:43 -05:00
|
|
|
let _icx = cx.insn_ctxt("trans_lit");
|
2012-08-06 14:34:08 -05:00
|
|
|
match lit.node {
|
2012-08-03 21:59:04 -05:00
|
|
|
ast::lit_int(i, t) => C_integral(T_int_ty(cx, t), i as u64, True),
|
|
|
|
ast::lit_uint(u, t) => C_integral(T_uint_ty(cx, t), u, False),
|
|
|
|
ast::lit_int_unsuffixed(i) => {
|
2012-07-31 20:34:36 -05:00
|
|
|
let lit_int_ty = ty::node_id_to_type(cx.tcx, e.id);
|
2012-09-11 18:20:31 -05:00
|
|
|
match ty::get(lit_int_ty).sty {
|
2012-08-03 21:59:04 -05:00
|
|
|
ty::ty_int(t) => {
|
2012-07-31 20:34:36 -05:00
|
|
|
C_integral(T_int_ty(cx, t), i as u64, True)
|
|
|
|
}
|
2012-08-03 21:59:04 -05:00
|
|
|
ty::ty_uint(t) => {
|
2012-07-31 20:34:36 -05:00
|
|
|
C_integral(T_uint_ty(cx, t), i as u64, False)
|
|
|
|
}
|
2012-08-03 21:59:04 -05:00
|
|
|
_ => cx.sess.span_bug(lit.span,
|
2013-03-20 14:55:18 -05:00
|
|
|
fmt!("integer literal has type %s (expected int or uint)",
|
|
|
|
ty_to_str(cx.tcx, lit_int_ty)))
|
2012-07-31 20:34:36 -05:00
|
|
|
}
|
|
|
|
}
|
2013-01-07 16:16:52 -06:00
|
|
|
ast::lit_float(fs, t) => C_floating(/*bad*/copy *fs, T_float_ty(cx, t)),
|
2012-11-07 20:40:34 -06:00
|
|
|
ast::lit_float_unsuffixed(fs) => {
|
|
|
|
let lit_float_ty = ty::node_id_to_type(cx.tcx, e.id);
|
|
|
|
match ty::get(lit_float_ty).sty {
|
|
|
|
ty::ty_float(t) => {
|
2013-01-07 16:16:52 -06:00
|
|
|
C_floating(/*bad*/copy *fs, T_float_ty(cx, t))
|
2012-11-07 20:40:34 -06:00
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
cx.sess.span_bug(lit.span,
|
|
|
|
~"floating point literal doesn't have the right \
|
|
|
|
type");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-08-03 21:59:04 -05:00
|
|
|
ast::lit_bool(b) => C_bool(b),
|
|
|
|
ast::lit_nil => C_nil(),
|
2013-02-10 18:33:16 -06:00
|
|
|
ast::lit_str(s) => C_estr_slice(cx, s)
|
2012-07-31 20:34:36 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-02-19 01:40:42 -06:00
|
|
|
pub fn const_ptrcast(cx: @CrateContext, a: ValueRef, t: TypeRef) -> ValueRef {
|
2013-01-10 23:23:07 -06:00
|
|
|
unsafe {
|
|
|
|
let b = llvm::LLVMConstPointerCast(a, T_ptr(t));
|
2013-03-28 20:39:09 -05:00
|
|
|
assert!(cx.const_globals.insert(b as int, a));
|
2013-01-10 23:23:07 -06:00
|
|
|
b
|
|
|
|
}
|
2012-08-09 18:05:34 -05:00
|
|
|
}
|
|
|
|
|
2013-02-19 01:40:42 -06:00
|
|
|
pub fn const_vec(cx: @CrateContext, e: @ast::expr, es: &[@ast::expr])
|
2012-08-07 17:04:40 -05:00
|
|
|
-> (ValueRef, ValueRef, TypeRef) {
|
2013-01-10 23:23:07 -06:00
|
|
|
unsafe {
|
|
|
|
let vec_ty = ty::expr_ty(cx.tcx, e);
|
|
|
|
let unit_ty = ty::sequence_element_type(cx.tcx, vec_ty);
|
|
|
|
let llunitty = type_of::type_of(cx, unit_ty);
|
2013-01-30 13:46:19 -06:00
|
|
|
let unit_sz = machine::llsize_of(cx, llunitty);
|
2013-01-10 23:23:07 -06:00
|
|
|
let sz = llvm::LLVMConstMul(C_uint(cx, es.len()), unit_sz);
|
2013-01-30 18:36:07 -06:00
|
|
|
let vs = es.map(|e| const_expr(cx, *e));
|
|
|
|
// If the vector contains enums, an LLVM array won't work.
|
|
|
|
let v = if vs.any(|vi| val_ty(*vi) != llunitty) {
|
|
|
|
C_struct(vs)
|
|
|
|
} else {
|
|
|
|
C_array(llunitty, vs)
|
|
|
|
};
|
2013-01-10 23:23:07 -06:00
|
|
|
return (v, sz, llunitty);
|
|
|
|
}
|
2012-08-03 23:44:42 -05:00
|
|
|
}
|
|
|
|
|
2013-03-07 14:34:39 -06:00
|
|
|
fn const_addr_of(cx: @CrateContext, cv: ValueRef) -> ValueRef {
|
|
|
|
unsafe {
|
|
|
|
let gv = do str::as_c_str("const") |name| {
|
|
|
|
llvm::LLVMAddGlobal(cx.llmod, val_ty(cv), name)
|
|
|
|
};
|
|
|
|
llvm::LLVMSetInitializer(gv, cv);
|
|
|
|
llvm::LLVMSetGlobalConstant(gv, True);
|
2013-03-28 20:15:35 -05:00
|
|
|
SetLinkage(gv, PrivateLinkage);
|
2013-03-07 14:34:39 -06:00
|
|
|
gv
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-03-08 12:22:48 -06:00
|
|
|
fn const_deref_ptr(cx: @CrateContext, v: ValueRef) -> ValueRef {
|
|
|
|
let v = match cx.const_globals.find(&(v as int)) {
|
2013-03-22 21:26:41 -05:00
|
|
|
Some(&v) => v,
|
2013-03-08 12:22:48 -06:00
|
|
|
None => v
|
|
|
|
};
|
2013-01-10 23:23:07 -06:00
|
|
|
unsafe {
|
2013-03-28 20:39:09 -05:00
|
|
|
assert!(llvm::LLVMIsGlobalConstant(v) == True);
|
2013-03-08 12:22:48 -06:00
|
|
|
llvm::LLVMGetInitializer(v)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn const_deref_newtype(cx: @CrateContext, v: ValueRef, t: ty::t)
|
|
|
|
-> ValueRef {
|
|
|
|
let repr = adt::represent_type(cx, t);
|
|
|
|
adt::const_get_field(cx, repr, v, 0, 0)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn const_deref(cx: @CrateContext, v: ValueRef, t: ty::t, explicit: bool)
|
|
|
|
-> (ValueRef, ty::t) {
|
|
|
|
match ty::deref(cx.tcx, t, explicit) {
|
|
|
|
Some(ref mt) => {
|
2013-03-28 20:39:09 -05:00
|
|
|
assert!(mt.mutbl != ast::m_mutbl);
|
2013-03-08 12:22:48 -06:00
|
|
|
let dv = match ty::get(t).sty {
|
|
|
|
ty::ty_ptr(*) | ty::ty_rptr(*) => {
|
|
|
|
const_deref_ptr(cx, v)
|
|
|
|
}
|
|
|
|
ty::ty_enum(*) | ty::ty_struct(*) => {
|
|
|
|
const_deref_newtype(cx, v, t)
|
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
cx.sess.bug(fmt!("Unexpected dereferenceable type %s",
|
|
|
|
ty_to_str(cx.tcx, t)))
|
|
|
|
}
|
|
|
|
};
|
|
|
|
(dv, mt.ty)
|
|
|
|
}
|
|
|
|
None => {
|
|
|
|
cx.sess.bug(fmt!("Can't dereference const of type %s",
|
|
|
|
ty_to_str(cx.tcx, t)))
|
|
|
|
}
|
2013-01-10 23:23:07 -06:00
|
|
|
}
|
2012-08-08 21:41:50 -05:00
|
|
|
}
|
|
|
|
|
2013-02-19 01:40:42 -06:00
|
|
|
pub fn get_const_val(cx: @CrateContext, def_id: ast::def_id) -> ValueRef {
|
2013-03-07 00:30:20 -06:00
|
|
|
let mut def_id = def_id;
|
|
|
|
if !ast_util::is_local(def_id) ||
|
|
|
|
!cx.const_values.contains_key(&def_id.node) {
|
|
|
|
if !ast_util::is_local(def_id) {
|
|
|
|
def_id = inline::maybe_instantiate_inline(cx, def_id, true);
|
|
|
|
}
|
2013-03-23 20:45:27 -05:00
|
|
|
match *cx.tcx.items.get(&def_id.node) {
|
2013-01-13 15:13:41 -06:00
|
|
|
ast_map::node_item(@ast::item {
|
2012-11-13 00:10:15 -06:00
|
|
|
node: ast::item_const(_, subexpr), _
|
|
|
|
}, _) => {
|
|
|
|
trans_const(cx, subexpr, def_id.node);
|
|
|
|
}
|
|
|
|
_ => cx.tcx.sess.bug(~"expected a const to be an item")
|
|
|
|
}
|
|
|
|
}
|
2013-03-22 21:26:41 -05:00
|
|
|
*cx.const_values.get(&def_id.node)
|
2012-11-13 00:10:15 -06:00
|
|
|
}
|
2012-08-08 21:41:50 -05:00
|
|
|
|
2013-02-19 01:40:42 -06:00
|
|
|
pub fn const_expr(cx: @CrateContext, e: @ast::expr) -> ValueRef {
|
2013-03-07 14:34:58 -06:00
|
|
|
let mut llconst = const_expr_unadjusted(cx, e);
|
|
|
|
let ety = ty::expr_ty(cx.tcx, e);
|
|
|
|
match cx.tcx.adjustments.find(&e.id) {
|
|
|
|
None => { }
|
2013-03-22 21:26:41 -05:00
|
|
|
Some(&@ty::AutoAddEnv(ty::re_static, ast::BorrowedSigil)) => {
|
2013-03-07 14:34:58 -06:00
|
|
|
llconst = C_struct(~[llconst, C_null(T_opaque_box_ptr(cx))])
|
|
|
|
}
|
2013-03-22 21:26:41 -05:00
|
|
|
Some(&@ty::AutoAddEnv(ref r, ref s)) => {
|
2013-03-22 16:00:15 -05:00
|
|
|
cx.sess.span_bug(e.span, fmt!("unexpected static function: \
|
2013-03-07 14:34:58 -06:00
|
|
|
region %? sigil %?", *r, *s))
|
|
|
|
}
|
2013-03-22 21:26:41 -05:00
|
|
|
Some(&@ty::AutoDerefRef(ref adj)) => {
|
2013-03-08 12:22:48 -06:00
|
|
|
let mut ty = ety;
|
2013-03-08 13:29:47 -06:00
|
|
|
let mut maybe_ptr = None;
|
2013-03-07 14:34:58 -06:00
|
|
|
for adj.autoderefs.times {
|
2013-03-08 12:22:48 -06:00
|
|
|
let (dv, dt) = const_deref(cx, llconst, ty, false);
|
2013-03-08 13:29:47 -06:00
|
|
|
maybe_ptr = Some(llconst);
|
2013-03-08 12:22:48 -06:00
|
|
|
llconst = dv;
|
|
|
|
ty = dt;
|
2013-03-07 14:34:58 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
match adj.autoref {
|
|
|
|
None => { }
|
|
|
|
Some(ref autoref) => {
|
2013-03-28 20:39:09 -05:00
|
|
|
assert!(autoref.region == ty::re_static);
|
|
|
|
assert!(autoref.mutbl != ast::m_mutbl);
|
2013-03-08 13:29:47 -06:00
|
|
|
// Don't copy data to do a deref+ref.
|
|
|
|
let llptr = match maybe_ptr {
|
|
|
|
Some(ptr) => ptr,
|
|
|
|
None => const_addr_of(cx, llconst)
|
|
|
|
};
|
2013-03-07 14:34:58 -06:00
|
|
|
match autoref.kind {
|
|
|
|
ty::AutoPtr => {
|
2013-03-08 13:29:47 -06:00
|
|
|
llconst = llptr;
|
2013-03-07 14:34:58 -06:00
|
|
|
}
|
|
|
|
ty::AutoBorrowVec => {
|
|
|
|
let size = machine::llsize_of(cx,
|
|
|
|
val_ty(llconst));
|
2013-03-28 20:39:09 -05:00
|
|
|
assert!(abi::slice_elt_base == 0);
|
|
|
|
assert!(abi::slice_elt_len == 1);
|
2013-03-08 13:29:47 -06:00
|
|
|
llconst = C_struct(~[llptr, size]);
|
2013-03-07 14:34:58 -06:00
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
cx.sess.span_bug(e.span,
|
|
|
|
fmt!("unimplemented const \
|
|
|
|
autoref %?", autoref))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
let ety_adjusted = ty::expr_ty_adjusted(cx.tcx, e);
|
|
|
|
let llty = type_of::sizing_type_of(cx, ety_adjusted);
|
2013-03-03 16:30:06 -06:00
|
|
|
let csize = machine::llsize_of_alloc(cx, val_ty(llconst));
|
|
|
|
let tsize = machine::llsize_of_alloc(cx, llty);
|
|
|
|
if csize != tsize {
|
|
|
|
unsafe {
|
2013-03-07 14:34:58 -06:00
|
|
|
// XXX these values could use some context
|
2013-03-03 16:30:06 -06:00
|
|
|
llvm::LLVMDumpValue(llconst);
|
2013-03-07 14:34:58 -06:00
|
|
|
llvm::LLVMDumpValue(C_undef(llty));
|
2013-03-03 16:30:06 -06:00
|
|
|
}
|
|
|
|
cx.sess.bug(fmt!("const %s of type %s has size %u instead of %u",
|
|
|
|
expr_repr(cx.tcx, e), ty_to_str(cx.tcx, ety),
|
|
|
|
csize, tsize));
|
|
|
|
}
|
|
|
|
llconst
|
|
|
|
}
|
|
|
|
|
2013-03-07 14:34:58 -06:00
|
|
|
fn const_expr_unadjusted(cx: @CrateContext, e: @ast::expr) -> ValueRef {
|
2013-01-10 23:23:07 -06:00
|
|
|
unsafe {
|
|
|
|
let _icx = cx.insn_ctxt("const_expr");
|
2013-03-20 00:17:42 -05:00
|
|
|
return match e.node {
|
2013-01-10 23:23:07 -06:00
|
|
|
ast::expr_lit(lit) => consts::const_lit(cx, e, *lit),
|
|
|
|
ast::expr_binary(b, e1, e2) => {
|
|
|
|
let te1 = const_expr(cx, e1);
|
|
|
|
let te2 = const_expr(cx, e2);
|
2012-07-31 20:34:36 -05:00
|
|
|
|
2013-01-10 23:23:07 -06:00
|
|
|
let te2 = base::cast_shift_const_rhs(b, te1, te2);
|
2012-07-31 20:34:36 -05:00
|
|
|
|
2013-01-10 23:23:07 -06:00
|
|
|
/* Neither type is bottom, and we expect them to be unified
|
|
|
|
* already, so the following is safe. */
|
|
|
|
let ty = ty::expr_ty(cx.tcx, e1);
|
|
|
|
let is_float = ty::type_is_fp(ty);
|
|
|
|
let signed = ty::type_is_signed(ty);
|
|
|
|
return match b {
|
|
|
|
ast::add => {
|
|
|
|
if is_float { llvm::LLVMConstFAdd(te1, te2) }
|
|
|
|
else { llvm::LLVMConstAdd(te1, te2) }
|
|
|
|
}
|
|
|
|
ast::subtract => {
|
|
|
|
if is_float { llvm::LLVMConstFSub(te1, te2) }
|
|
|
|
else { llvm::LLVMConstSub(te1, te2) }
|
|
|
|
}
|
|
|
|
ast::mul => {
|
|
|
|
if is_float { llvm::LLVMConstFMul(te1, te2) }
|
|
|
|
else { llvm::LLVMConstMul(te1, te2) }
|
|
|
|
}
|
|
|
|
ast::div => {
|
|
|
|
if is_float { llvm::LLVMConstFDiv(te1, te2) }
|
|
|
|
else if signed { llvm::LLVMConstSDiv(te1, te2) }
|
|
|
|
else { llvm::LLVMConstUDiv(te1, te2) }
|
|
|
|
}
|
|
|
|
ast::rem => {
|
|
|
|
if is_float { llvm::LLVMConstFRem(te1, te2) }
|
|
|
|
else if signed { llvm::LLVMConstSRem(te1, te2) }
|
|
|
|
else { llvm::LLVMConstURem(te1, te2) }
|
|
|
|
}
|
|
|
|
ast::and |
|
|
|
|
ast::or => cx.sess.span_unimpl(e.span, ~"binop logic"),
|
|
|
|
ast::bitxor => llvm::LLVMConstXor(te1, te2),
|
|
|
|
ast::bitand => llvm::LLVMConstAnd(te1, te2),
|
|
|
|
ast::bitor => llvm::LLVMConstOr(te1, te2),
|
|
|
|
ast::shl => llvm::LLVMConstShl(te1, te2),
|
|
|
|
ast::shr => {
|
|
|
|
if signed { llvm::LLVMConstAShr(te1, te2) }
|
|
|
|
else { llvm::LLVMConstLShr(te1, te2) }
|
|
|
|
}
|
|
|
|
ast::eq |
|
|
|
|
ast::lt |
|
|
|
|
ast::le |
|
|
|
|
ast::ne |
|
|
|
|
ast::ge |
|
|
|
|
ast::gt => cx.sess.span_unimpl(e.span, ~"binop comparator")
|
|
|
|
}
|
2012-07-31 20:34:36 -05:00
|
|
|
}
|
2013-01-10 23:23:07 -06:00
|
|
|
ast::expr_unary(u, e) => {
|
|
|
|
let te = const_expr(cx, e);
|
|
|
|
let ty = ty::expr_ty(cx.tcx, e);
|
|
|
|
let is_float = ty::type_is_fp(ty);
|
|
|
|
return match u {
|
|
|
|
ast::box(_) |
|
|
|
|
ast::uniq(_) |
|
2013-03-08 12:22:48 -06:00
|
|
|
ast::deref => {
|
|
|
|
let (dv, _dt) = const_deref(cx, te, ty, true);
|
|
|
|
dv
|
|
|
|
}
|
2013-02-06 17:37:34 -06:00
|
|
|
ast::not => {
|
|
|
|
match ty::get(ty).sty {
|
|
|
|
ty::ty_bool => {
|
|
|
|
// Somewhat questionable, but I believe this is
|
|
|
|
// correct.
|
|
|
|
let te = llvm::LLVMConstTrunc(te, T_i1());
|
|
|
|
let te = llvm::LLVMConstNot(te);
|
|
|
|
llvm::LLVMConstZExt(te, T_bool())
|
|
|
|
}
|
|
|
|
_ => llvm::LLVMConstNot(te),
|
|
|
|
}
|
|
|
|
}
|
2013-01-10 23:23:07 -06:00
|
|
|
ast::neg => {
|
|
|
|
if is_float { llvm::LLVMConstFNeg(te) }
|
|
|
|
else { llvm::LLVMConstNeg(te) }
|
|
|
|
}
|
|
|
|
}
|
2012-07-31 20:34:36 -05:00
|
|
|
}
|
2013-01-10 23:23:07 -06:00
|
|
|
ast::expr_field(base, field, _) => {
|
2013-03-07 14:34:58 -06:00
|
|
|
let bt = ty::expr_ty_adjusted(cx.tcx, base);
|
2013-02-24 17:03:47 -06:00
|
|
|
let brepr = adt::represent_type(cx, bt);
|
2013-01-10 23:23:07 -06:00
|
|
|
let bv = const_expr(cx, base);
|
2013-02-24 17:03:47 -06:00
|
|
|
do expr::with_field_tys(cx.tcx, bt, None) |discr, field_tys| {
|
2013-01-10 23:23:07 -06:00
|
|
|
let ix = ty::field_idx_strict(cx.tcx, field, field_tys);
|
2013-03-02 18:08:49 -06:00
|
|
|
adt::const_get_field(cx, brepr, bv, discr, ix)
|
2013-01-10 23:23:07 -06:00
|
|
|
}
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
2012-08-08 21:41:50 -05:00
|
|
|
|
2013-01-10 23:23:07 -06:00
|
|
|
ast::expr_index(base, index) => {
|
2013-03-07 14:34:58 -06:00
|
|
|
let bt = ty::expr_ty_adjusted(cx.tcx, base);
|
2013-01-10 23:23:07 -06:00
|
|
|
let bv = const_expr(cx, base);
|
|
|
|
let iv = match const_eval::eval_const_expr(cx.tcx, index) {
|
|
|
|
const_eval::const_int(i) => i as u64,
|
|
|
|
const_eval::const_uint(u) => u,
|
|
|
|
_ => cx.sess.span_bug(index.span,
|
|
|
|
~"index is not an integer-constant \
|
|
|
|
expression")
|
|
|
|
};
|
2013-02-08 03:52:55 -06:00
|
|
|
let (arr, len) = match ty::get(bt).sty {
|
2013-01-10 23:23:07 -06:00
|
|
|
ty::ty_evec(_, vstore) | ty::ty_estr(vstore) =>
|
|
|
|
match vstore {
|
|
|
|
ty::vstore_fixed(u) =>
|
|
|
|
(bv, C_uint(cx, u)),
|
2012-08-08 21:41:50 -05:00
|
|
|
|
2013-01-10 23:23:07 -06:00
|
|
|
ty::vstore_slice(_) => {
|
|
|
|
let unit_ty = ty::sequence_element_type(cx.tcx, bt);
|
|
|
|
let llunitty = type_of::type_of(cx, unit_ty);
|
2013-01-30 13:46:19 -06:00
|
|
|
let unit_sz = machine::llsize_of(cx, llunitty);
|
2012-08-09 18:05:34 -05:00
|
|
|
|
2013-03-08 12:22:48 -06:00
|
|
|
(const_deref_ptr(cx, const_get_elt(cx, bv, [0])),
|
2013-01-10 23:23:07 -06:00
|
|
|
llvm::LLVMConstUDiv(const_get_elt(cx, bv, [1]),
|
|
|
|
unit_sz))
|
|
|
|
},
|
|
|
|
_ => cx.sess.span_bug(base.span,
|
|
|
|
~"index-expr base must be \
|
|
|
|
fixed-size or slice")
|
2012-08-08 21:41:50 -05:00
|
|
|
},
|
2013-01-10 23:23:07 -06:00
|
|
|
_ => cx.sess.span_bug(base.span,
|
|
|
|
~"index-expr base must be \
|
|
|
|
a vector or string type")
|
|
|
|
};
|
2012-08-09 18:05:34 -05:00
|
|
|
|
2013-02-08 03:52:55 -06:00
|
|
|
let len = llvm::LLVMConstIntGetZExtValue(len) as u64;
|
2013-01-10 23:23:07 -06:00
|
|
|
let len = match ty::get(bt).sty {
|
2013-03-28 20:39:09 -05:00
|
|
|
ty::ty_estr(*) => {assert!(len > 0); len - 1},
|
2013-01-10 23:23:07 -06:00
|
|
|
_ => len
|
|
|
|
};
|
|
|
|
if iv >= len {
|
|
|
|
// FIXME #3170: report this earlier on in the const-eval
|
|
|
|
// pass. Reporting here is a bit late.
|
|
|
|
cx.sess.span_err(e.span,
|
|
|
|
~"const index-expr is out of bounds");
|
|
|
|
}
|
|
|
|
const_get_elt(cx, arr, [iv as c_uint])
|
2012-08-08 21:41:50 -05:00
|
|
|
}
|
2013-01-10 23:23:07 -06:00
|
|
|
ast::expr_cast(base, _) => {
|
|
|
|
let ety = ty::expr_ty(cx.tcx, e);
|
|
|
|
let llty = type_of::type_of(cx, ety);
|
|
|
|
let basety = ty::expr_ty(cx.tcx, base);
|
|
|
|
let v = const_expr(cx, base);
|
|
|
|
match (expr::cast_type_kind(basety),
|
|
|
|
expr::cast_type_kind(ety)) {
|
2012-08-06 14:34:08 -05:00
|
|
|
|
2013-01-10 23:23:07 -06:00
|
|
|
(expr::cast_integral, expr::cast_integral) => {
|
2013-03-01 03:40:23 -06:00
|
|
|
let s = ty::type_is_signed(basety) as Bool;
|
2013-01-10 23:23:07 -06:00
|
|
|
llvm::LLVMConstIntCast(v, llty, s)
|
|
|
|
}
|
|
|
|
(expr::cast_integral, expr::cast_float) => {
|
|
|
|
if ty::type_is_signed(basety) {
|
|
|
|
llvm::LLVMConstSIToFP(v, llty)
|
|
|
|
} else {
|
|
|
|
llvm::LLVMConstUIToFP(v, llty)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
(expr::cast_float, expr::cast_float) => {
|
|
|
|
llvm::LLVMConstFPCast(v, llty)
|
|
|
|
}
|
|
|
|
(expr::cast_float, expr::cast_integral) => {
|
|
|
|
if ty::type_is_signed(ety) { llvm::LLVMConstFPToSI(v, llty) }
|
|
|
|
else { llvm::LLVMConstFPToUI(v, llty) }
|
|
|
|
}
|
2013-03-01 03:40:23 -06:00
|
|
|
(expr::cast_enum, expr::cast_integral) |
|
|
|
|
(expr::cast_enum, expr::cast_float) => {
|
2013-02-24 16:38:59 -06:00
|
|
|
let repr = adt::represent_type(cx, basety);
|
2013-02-25 03:49:21 -06:00
|
|
|
let iv = C_int(cx, adt::const_get_discrim(cx, repr, v));
|
2013-03-01 03:40:23 -06:00
|
|
|
let ety_cast = expr::cast_type_kind(ety);
|
|
|
|
match ety_cast {
|
|
|
|
expr::cast_integral => {
|
|
|
|
let s = ty::type_is_signed(ety) as Bool;
|
|
|
|
llvm::LLVMConstIntCast(iv, llty, s)
|
|
|
|
}
|
|
|
|
expr::cast_float => llvm::LLVMConstUIToFP(iv, llty),
|
|
|
|
_ => cx.sess.bug(~"enum cast destination is not \
|
|
|
|
integral or float")
|
|
|
|
}
|
|
|
|
}
|
2013-03-04 17:22:03 -06:00
|
|
|
(expr::cast_pointer, expr::cast_pointer) => {
|
|
|
|
llvm::LLVMConstPointerCast(v, llty)
|
|
|
|
}
|
2013-03-07 14:35:43 -06:00
|
|
|
(expr::cast_integral, expr::cast_pointer) => {
|
|
|
|
llvm::LLVMConstIntToPtr(v, llty)
|
|
|
|
}
|
2013-01-10 23:23:07 -06:00
|
|
|
_ => {
|
|
|
|
cx.sess.impossible_case(e.span,
|
|
|
|
~"bad combination of types for cast")
|
|
|
|
}
|
2012-08-03 23:44:42 -05:00
|
|
|
}
|
|
|
|
}
|
2013-01-10 23:23:07 -06:00
|
|
|
ast::expr_addr_of(ast::m_imm, sub) => {
|
2013-03-07 14:34:39 -06:00
|
|
|
const_addr_of(cx, const_expr(cx, sub))
|
2012-08-03 23:44:42 -05:00
|
|
|
}
|
2013-03-20 00:17:42 -05:00
|
|
|
ast::expr_tup(ref es) => {
|
2013-02-24 16:38:59 -06:00
|
|
|
let ety = ty::expr_ty(cx.tcx, e);
|
|
|
|
let repr = adt::represent_type(cx, ety);
|
2013-02-25 03:49:21 -06:00
|
|
|
adt::trans_const(cx, repr, 0, es.map(|e| const_expr(cx, *e)))
|
2013-01-10 23:23:07 -06:00
|
|
|
}
|
2013-02-24 16:38:59 -06:00
|
|
|
ast::expr_struct(_, ref fs, None) => {
|
2013-01-10 23:23:07 -06:00
|
|
|
let ety = ty::expr_ty(cx.tcx, e);
|
2013-02-24 16:38:59 -06:00
|
|
|
let repr = adt::represent_type(cx, ety);
|
|
|
|
do expr::with_field_tys(cx.tcx, ety, Some(e.id))
|
|
|
|
|discr, field_tys| {
|
|
|
|
let cs = field_tys.map(|field_ty| {
|
2013-01-10 23:23:07 -06:00
|
|
|
match fs.find(|f| field_ty.ident == f.node.ident) {
|
|
|
|
Some(ref f) => const_expr(cx, (*f).node.expr),
|
|
|
|
None => {
|
|
|
|
cx.tcx.sess.span_bug(
|
|
|
|
e.span, ~"missing struct field");
|
|
|
|
}
|
|
|
|
}
|
2013-02-24 16:38:59 -06:00
|
|
|
});
|
2013-02-25 03:49:21 -06:00
|
|
|
adt::trans_const(cx, repr, discr, cs)
|
2013-02-24 16:38:59 -06:00
|
|
|
}
|
2013-01-10 23:23:07 -06:00
|
|
|
}
|
2013-03-20 00:17:42 -05:00
|
|
|
ast::expr_vec(ref es, ast::m_imm) => {
|
|
|
|
let (v, _, _) = const_vec(cx, e, *es);
|
2013-01-10 23:23:07 -06:00
|
|
|
v
|
|
|
|
}
|
|
|
|
ast::expr_vstore(sub, ast::expr_vstore_slice) => {
|
2013-03-20 00:17:42 -05:00
|
|
|
match sub.node {
|
|
|
|
ast::expr_lit(ref lit) => {
|
2013-01-10 23:23:07 -06:00
|
|
|
match lit.node {
|
|
|
|
ast::lit_str(*) => { const_expr(cx, sub) }
|
|
|
|
_ => { cx.sess.span_bug(e.span,
|
|
|
|
~"bad const-slice lit") }
|
|
|
|
}
|
|
|
|
}
|
2013-03-20 00:17:42 -05:00
|
|
|
ast::expr_vec(ref es, ast::m_imm) => {
|
|
|
|
let (cv, sz, llunitty) = const_vec(cx, e, *es);
|
2013-01-10 23:23:07 -06:00
|
|
|
let llty = val_ty(cv);
|
|
|
|
let gv = do str::as_c_str("const") |name| {
|
|
|
|
llvm::LLVMAddGlobal(cx.llmod, llty, name)
|
|
|
|
};
|
|
|
|
llvm::LLVMSetInitializer(gv, cv);
|
|
|
|
llvm::LLVMSetGlobalConstant(gv, True);
|
2013-03-28 20:15:35 -05:00
|
|
|
SetLinkage(gv, PrivateLinkage);
|
2013-01-10 23:23:07 -06:00
|
|
|
let p = const_ptrcast(cx, gv, llunitty);
|
|
|
|
C_struct(~[p, sz])
|
|
|
|
}
|
|
|
|
_ => cx.sess.span_bug(e.span,
|
|
|
|
~"bad const-slice expr")
|
2012-11-30 15:25:43 -06:00
|
|
|
}
|
2013-01-10 23:23:07 -06:00
|
|
|
}
|
|
|
|
ast::expr_path(pth) => {
|
2013-03-28 20:39:09 -05:00
|
|
|
assert!(pth.types.len() == 0);
|
2013-02-05 21:41:45 -06:00
|
|
|
match cx.tcx.def_map.find(&e.id) {
|
2013-03-22 21:26:41 -05:00
|
|
|
Some(&ast::def_fn(def_id, _purity)) => {
|
2013-03-07 14:34:58 -06:00
|
|
|
if !ast_util::is_local(def_id) {
|
2013-03-07 00:30:20 -06:00
|
|
|
let ty = csearch::get_type(cx.tcx, def_id).ty;
|
|
|
|
base::trans_external_path(cx, def_id, ty)
|
|
|
|
} else {
|
2013-03-28 20:39:09 -05:00
|
|
|
assert!(ast_util::is_local(def_id));
|
2013-03-07 00:30:20 -06:00
|
|
|
base::get_item_val(cx, def_id.node)
|
2013-01-18 09:12:07 -06:00
|
|
|
}
|
2013-01-10 23:23:07 -06:00
|
|
|
}
|
2013-03-22 21:26:41 -05:00
|
|
|
Some(&ast::def_const(def_id)) => {
|
2013-01-10 23:23:07 -06:00
|
|
|
get_const_val(cx, def_id)
|
2012-11-30 15:25:43 -06:00
|
|
|
}
|
2013-03-22 21:26:41 -05:00
|
|
|
Some(&ast::def_variant(enum_did, variant_did)) => {
|
2013-01-30 18:08:39 -06:00
|
|
|
let ety = ty::expr_ty(cx.tcx, e);
|
2013-02-24 16:38:59 -06:00
|
|
|
let repr = adt::represent_type(cx, ety);
|
|
|
|
let vinfo = ty::enum_variant_with_id(cx.tcx,
|
|
|
|
enum_did,
|
|
|
|
variant_did);
|
2013-02-25 03:49:21 -06:00
|
|
|
adt::trans_const(cx, repr, vinfo.disr_val, [])
|
2013-01-07 05:42:49 -06:00
|
|
|
}
|
2013-03-22 21:26:41 -05:00
|
|
|
Some(&ast::def_struct(_)) => {
|
2013-01-10 23:23:07 -06:00
|
|
|
let ety = ty::expr_ty(cx.tcx, e);
|
|
|
|
let llty = type_of::type_of(cx, ety);
|
|
|
|
C_null(llty)
|
|
|
|
}
|
|
|
|
_ => {
|
2013-02-24 16:38:59 -06:00
|
|
|
cx.sess.span_bug(e.span, ~"expected a const, fn, \
|
|
|
|
struct, or variant def")
|
2013-01-10 23:23:07 -06:00
|
|
|
}
|
2012-11-30 15:25:43 -06:00
|
|
|
}
|
2013-01-10 23:23:07 -06:00
|
|
|
}
|
2013-03-20 00:17:42 -05:00
|
|
|
ast::expr_call(callee, ref args, _) => {
|
2013-02-24 16:38:59 -06:00
|
|
|
match cx.tcx.def_map.find(&callee.id) {
|
2013-03-22 21:26:41 -05:00
|
|
|
Some(&ast::def_struct(_)) => {
|
2013-02-24 16:38:59 -06:00
|
|
|
let ety = ty::expr_ty(cx.tcx, e);
|
|
|
|
let repr = adt::represent_type(cx, ety);
|
2013-02-25 03:49:21 -06:00
|
|
|
adt::trans_const(cx, repr, 0,
|
2013-02-24 16:38:59 -06:00
|
|
|
args.map(|a| const_expr(cx, *a)))
|
|
|
|
}
|
2013-03-22 21:26:41 -05:00
|
|
|
Some(&ast::def_variant(enum_did, variant_did)) => {
|
2013-02-24 16:38:59 -06:00
|
|
|
let ety = ty::expr_ty(cx.tcx, e);
|
|
|
|
let repr = adt::represent_type(cx, ety);
|
|
|
|
let vinfo = ty::enum_variant_with_id(cx.tcx,
|
|
|
|
enum_did,
|
|
|
|
variant_did);
|
2013-02-25 03:49:21 -06:00
|
|
|
adt::trans_const(cx, repr, vinfo.disr_val,
|
2013-02-24 16:38:59 -06:00
|
|
|
args.map(|a| const_expr(cx, *a)))
|
|
|
|
}
|
|
|
|
_ => cx.sess.span_bug(e.span, ~"expected a struct or \
|
|
|
|
variant def")
|
|
|
|
}
|
2013-01-10 23:23:07 -06:00
|
|
|
}
|
|
|
|
ast::expr_paren(e) => { return const_expr(cx, e); }
|
|
|
|
_ => cx.sess.span_bug(e.span,
|
|
|
|
~"bad constant expression type in consts::const_expr")
|
|
|
|
};
|
|
|
|
}
|
2012-07-31 20:34:36 -05:00
|
|
|
}
|
|
|
|
|
2013-02-19 01:40:42 -06:00
|
|
|
pub fn trans_const(ccx: @CrateContext, _e: @ast::expr, id: ast::node_id) {
|
2013-01-10 23:23:07 -06:00
|
|
|
unsafe {
|
|
|
|
let _icx = ccx.insn_ctxt("trans_const");
|
|
|
|
let g = base::get_item_val(ccx, id);
|
2012-12-30 22:30:23 -06:00
|
|
|
// At this point, get_item_val has already translated the
|
|
|
|
// constant's initializer to determine its LLVM type.
|
2013-03-22 21:26:41 -05:00
|
|
|
let v = *ccx.const_values.get(&id);
|
2013-01-10 23:23:07 -06:00
|
|
|
llvm::LLVMSetInitializer(g, v);
|
|
|
|
llvm::LLVMSetGlobalConstant(g, True);
|
|
|
|
}
|
2012-07-31 20:34:36 -05:00
|
|
|
}
|