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-05-17 17:28:44 -05:00
|
|
|
use core::prelude::*;
|
|
|
|
|
2013-03-07 14:34:58 -06:00
|
|
|
use back::abi;
|
2013-05-19 19:18:56 -05:00
|
|
|
use lib::llvm::{llvm, ConstFCmp, ConstICmp, SetLinkage, PrivateLinkage, ValueRef, TypeRef, Bool,
|
|
|
|
True, False};
|
2013-05-19 15:03:52 -05:00
|
|
|
use lib::llvm::{IntEQ, IntNE, IntUGT, IntUGE, IntULT, IntULE, IntSGT, IntSGE, IntSLT, IntSLE,
|
|
|
|
RealOEQ, RealOGT, RealOGE, RealOLT, RealOLE, RealONE};
|
|
|
|
|
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;
|
Cleanup substitutions and treatment of generics around traits in a number of ways.
- In a TraitRef, use the self type consistently to refer to the Self type:
- trait ref in `impl Trait<A,B,C> for S` has a self type of `S`.
- trait ref in `A:Trait` has the self type `A`
- trait ref associated with a trait decl has self type `Self`
- trait ref associated with a supertype has self type `Self`
- trait ref in an object type `@Trait` has no self type
- Rewrite `each_bound_traits_and_supertraits` to perform
substitutions as it goes, and thus yield a series of trait refs
that are always in the same 'namespace' as the type parameter
bound given as input. Before, we left this to the caller, but
this doesn't work because the caller lacks adequare information
to perform the type substitutions correctly.
- For provided methods, substitute the generics involved in the provided
method correctly.
- Introduce TypeParameterDef, which tracks the bounds declared on a type
parameter and brings them together with the def_id and (in the future)
other information (maybe even the parameter's name!).
- Introduce Subst trait, which helps to cleanup a lot of the
repetitive code involved with doing type substitution.
- Introduce Repr trait, which makes debug printouts far more convenient.
Fixes #4183. Needed for #5656.
2013-04-09 00:54:49 -05:00
|
|
|
use util::ppaux::{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-05-24 21:35:29 -05:00
|
|
|
use core::str;
|
2013-03-26 15:38:07 -05:00
|
|
|
use syntax::{ast, ast_util, ast_map};
|
2012-07-31 20:34:36 -05:00
|
|
|
|
2013-06-13 02:19:50 -05:00
|
|
|
pub fn const_lit(cx: @mut 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-06-12 12:02:55 -05:00
|
|
|
ast::lit_float(fs, t) => C_floating(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-06-12 12:02:55 -05:00
|
|
|
C_floating(fs, T_float_ty(cx, t))
|
2012-11-07 20:40:34 -06:00
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
cx.sess.span_bug(lit.span,
|
2013-05-02 11:28:53 -05:00
|
|
|
"floating point literal doesn't have the right type");
|
2012-11-07 20:40:34 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
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-06-13 02:19:50 -05:00
|
|
|
pub fn const_ptrcast(cx: &mut 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-06-13 02:19:50 -05:00
|
|
|
pub fn const_vec(cx: @mut 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-06-13 02:19:50 -05:00
|
|
|
fn const_addr_of(cx: @mut CrateContext, cv: ValueRef) -> ValueRef {
|
2013-03-07 14:34:39 -06:00
|
|
|
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-06-13 02:19:50 -05:00
|
|
|
fn const_deref_ptr(cx: @mut CrateContext, v: ValueRef) -> ValueRef {
|
2013-03-08 12:22:48 -06:00
|
|
|
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-05-18 21:02:45 -05:00
|
|
|
assert_eq!(llvm::LLVMIsGlobalConstant(v), True);
|
2013-03-08 12:22:48 -06:00
|
|
|
llvm::LLVMGetInitializer(v)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-13 02:19:50 -05:00
|
|
|
fn const_deref_newtype(cx: @mut CrateContext, v: ValueRef, t: ty::t)
|
2013-03-08 12:22:48 -06:00
|
|
|
-> ValueRef {
|
|
|
|
let repr = adt::represent_type(cx, t);
|
|
|
|
adt::const_get_field(cx, repr, v, 0, 0)
|
|
|
|
}
|
|
|
|
|
2013-06-13 02:19:50 -05:00
|
|
|
fn const_deref(cx: @mut CrateContext, v: ValueRef, t: ty::t, explicit: bool)
|
2013-03-08 12:22:48 -06:00
|
|
|
-> (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-06-13 02:19:50 -05:00
|
|
|
pub fn get_const_val(cx: @mut CrateContext, mut def_id: ast::def_id) -> ValueRef {
|
|
|
|
let contains_key = cx.const_values.contains_key(&def_id.node);
|
|
|
|
if !ast_util::is_local(def_id) || !contains_key {
|
2013-03-07 00:30:20 -06:00
|
|
|
if !ast_util::is_local(def_id) {
|
|
|
|
def_id = inline::maybe_instantiate_inline(cx, def_id, true);
|
|
|
|
}
|
2013-05-05 11:17:59 -05:00
|
|
|
match cx.tcx.items.get_copy(&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);
|
|
|
|
}
|
2013-05-19 00:07:44 -05:00
|
|
|
_ => cx.tcx.sess.bug("expected a const to be an item")
|
2012-11-13 00:10:15 -06:00
|
|
|
}
|
|
|
|
}
|
2013-05-05 11:17:59 -05:00
|
|
|
cx.const_values.get_copy(&def_id.node)
|
2012-11-13 00:10:15 -06:00
|
|
|
}
|
2012-08-08 21:41:50 -05:00
|
|
|
|
2013-06-13 02:19:50 -05:00
|
|
|
pub fn const_expr(cx: @mut 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);
|
2013-06-13 02:19:50 -05:00
|
|
|
let adjustment = cx.tcx.adjustments.find_copy(&e.id);
|
|
|
|
match adjustment {
|
2013-03-07 14:34:58 -06:00
|
|
|
None => { }
|
2013-06-13 02:19:50 -05:00
|
|
|
Some(@ty::AutoAddEnv(ty::re_static, ast::BorrowedSigil)) => {
|
2013-05-19 00:07:44 -05:00
|
|
|
llconst = C_struct([llconst, C_null(T_opaque_box_ptr(cx))])
|
2013-03-07 14:34:58 -06:00
|
|
|
}
|
2013-06-13 02:19:50 -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-06-13 02:19:50 -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-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-15 14:24:24 -05:00
|
|
|
match *autoref {
|
|
|
|
ty::AutoUnsafe(m) |
|
|
|
|
ty::AutoPtr(ty::re_static, m) => {
|
|
|
|
assert!(m != ast::m_mutbl);
|
2013-03-08 13:29:47 -06:00
|
|
|
llconst = llptr;
|
2013-03-07 14:34:58 -06:00
|
|
|
}
|
2013-03-15 14:24:24 -05:00
|
|
|
ty::AutoBorrowVec(ty::re_static, m) => {
|
|
|
|
assert!(m != ast::m_mutbl);
|
2013-03-07 14:34:58 -06:00
|
|
|
let size = machine::llsize_of(cx,
|
|
|
|
val_ty(llconst));
|
2013-05-18 21:02:45 -05:00
|
|
|
assert_eq!(abi::slice_elt_base, 0);
|
|
|
|
assert_eq!(abi::slice_elt_len, 1);
|
2013-05-19 00:07:44 -05: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",
|
Cleanup substitutions and treatment of generics around traits in a number of ways.
- In a TraitRef, use the self type consistently to refer to the Self type:
- trait ref in `impl Trait<A,B,C> for S` has a self type of `S`.
- trait ref in `A:Trait` has the self type `A`
- trait ref associated with a trait decl has self type `Self`
- trait ref associated with a supertype has self type `Self`
- trait ref in an object type `@Trait` has no self type
- Rewrite `each_bound_traits_and_supertraits` to perform
substitutions as it goes, and thus yield a series of trait refs
that are always in the same 'namespace' as the type parameter
bound given as input. Before, we left this to the caller, but
this doesn't work because the caller lacks adequare information
to perform the type substitutions correctly.
- For provided methods, substitute the generics involved in the provided
method correctly.
- Introduce TypeParameterDef, which tracks the bounds declared on a type
parameter and brings them together with the def_id and (in the future)
other information (maybe even the parameter's name!).
- Introduce Subst trait, which helps to cleanup a lot of the
repetitive code involved with doing type substitution.
- Introduce Repr trait, which makes debug printouts far more convenient.
Fixes #4183. Needed for #5656.
2013-04-09 00:54:49 -05:00
|
|
|
e.repr(cx.tcx), ty_to_str(cx.tcx, ety),
|
2013-03-03 16:30:06 -06:00
|
|
|
csize, tsize));
|
|
|
|
}
|
|
|
|
llconst
|
|
|
|
}
|
|
|
|
|
2013-06-13 02:19:50 -05:00
|
|
|
fn const_expr_unadjusted(cx: @mut 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),
|
2013-06-01 17:31:56 -05:00
|
|
|
ast::expr_binary(_, b, e1, e2) => {
|
2013-01-10 23:23:07 -06:00
|
|
|
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) }
|
|
|
|
}
|
2013-05-01 00:40:05 -05:00
|
|
|
ast::div => {
|
2013-01-10 23:23:07 -06:00
|
|
|
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) }
|
|
|
|
}
|
2013-05-19 15:03:52 -05:00
|
|
|
ast::and => llvm::LLVMConstAnd(te1, te2),
|
|
|
|
ast::or => llvm::LLVMConstOr(te1, te2),
|
2013-01-10 23:23:07 -06:00
|
|
|
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) }
|
|
|
|
}
|
2013-05-19 15:03:52 -05:00
|
|
|
ast::eq => {
|
2013-05-19 19:18:56 -05:00
|
|
|
if is_float { ConstFCmp(RealOEQ, te1, te2) }
|
|
|
|
else { ConstICmp(IntEQ, te1, te2) }
|
2013-05-19 15:03:52 -05:00
|
|
|
},
|
|
|
|
ast::lt => {
|
2013-05-19 19:18:56 -05:00
|
|
|
if is_float { ConstFCmp(RealOLT, te1, te2) }
|
2013-05-19 15:03:52 -05:00
|
|
|
else {
|
2013-05-19 19:18:56 -05:00
|
|
|
if signed { ConstICmp(IntSLT, te1, te2) }
|
|
|
|
else { ConstICmp(IntULT, te1, te2) }
|
2013-05-19 15:03:52 -05:00
|
|
|
}
|
|
|
|
},
|
|
|
|
ast::le => {
|
2013-05-19 19:18:56 -05:00
|
|
|
if is_float { ConstFCmp(RealOLE, te1, te2) }
|
2013-05-19 15:03:52 -05:00
|
|
|
else {
|
2013-05-19 19:18:56 -05:00
|
|
|
if signed { ConstICmp(IntSLE, te1, te2) }
|
|
|
|
else { ConstICmp(IntULE, te1, te2) }
|
2013-05-19 15:03:52 -05:00
|
|
|
}
|
|
|
|
},
|
|
|
|
ast::ne => {
|
2013-05-19 19:18:56 -05:00
|
|
|
if is_float { ConstFCmp(RealONE, te1, te2) }
|
|
|
|
else { ConstICmp(IntNE, te1, te2) }
|
2013-05-19 15:03:52 -05:00
|
|
|
},
|
|
|
|
ast::ge => {
|
2013-05-19 19:18:56 -05:00
|
|
|
if is_float { ConstFCmp(RealOGE, te1, te2) }
|
2013-05-19 15:03:52 -05:00
|
|
|
else {
|
2013-05-19 19:18:56 -05:00
|
|
|
if signed { ConstICmp(IntSGE, te1, te2) }
|
|
|
|
else { ConstICmp(IntUGE, te1, te2) }
|
2013-05-19 15:03:52 -05:00
|
|
|
}
|
|
|
|
},
|
|
|
|
ast::gt => {
|
2013-05-19 19:18:56 -05:00
|
|
|
if is_float { ConstFCmp(RealOGT, te1, te2) }
|
2013-05-19 15:03:52 -05:00
|
|
|
else {
|
2013-05-19 19:18:56 -05:00
|
|
|
if signed { ConstICmp(IntSGT, te1, te2) }
|
|
|
|
else { ConstICmp(IntUGT, te1, te2) }
|
2013-05-19 15:03:52 -05:00
|
|
|
}
|
|
|
|
},
|
|
|
|
};
|
|
|
|
},
|
2013-06-01 17:31:56 -05:00
|
|
|
ast::expr_unary(_, u, e) => {
|
2013-01-10 23:23:07 -06:00
|
|
|
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-06-01 17:31:56 -05: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,
|
2013-05-02 11:28:53 -05:00
|
|
|
"index is not an integer-constant expression")
|
2013-01-10 23:23:07 -06:00
|
|
|
};
|
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,
|
2013-05-02 11:28:53 -05:00
|
|
|
"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,
|
2013-05-02 11:28:53 -05:00
|
|
|
"index-expr base must be a vector or string type")
|
2013-01-10 23:23:07 -06:00
|
|
|
};
|
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,
|
2013-05-02 11:28:53 -05:00
|
|
|
"const index-expr is out of bounds");
|
2013-01-10 23:23:07 -06:00
|
|
|
}
|
|
|
|
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-06-13 02:19:50 -05:00
|
|
|
let discr = adt::const_get_discrim(cx, repr, v);
|
|
|
|
let iv = C_int(cx, discr);
|
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),
|
2013-05-19 00:07:44 -05:00
|
|
|
_ => cx.sess.bug("enum cast destination is not \
|
|
|
|
integral or float")
|
2013-03-01 03:40:23 -06:00
|
|
|
}
|
|
|
|
}
|
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,
|
2013-05-19 00:07:44 -05:00
|
|
|
"bad combination of types for cast")
|
2013-01-10 23:23:07 -06:00
|
|
|
}
|
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-06-13 02:19:50 -05:00
|
|
|
let e = const_expr(cx, sub);
|
|
|
|
const_addr_of(cx, e)
|
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-06-13 02:19:50 -05:00
|
|
|
let vals = es.map(|&e| const_expr(cx, e));
|
|
|
|
adt::trans_const(cx, repr, 0, vals)
|
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);
|
2013-06-13 02:19:50 -05:00
|
|
|
let tcx = cx.tcx;
|
|
|
|
do expr::with_field_tys(tcx, ety, Some(e.id))
|
2013-02-24 16:38:59 -06:00
|
|
|
|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 => {
|
2013-05-02 11:28:53 -05:00
|
|
|
cx.tcx.sess.span_bug(e.span, "missing struct field");
|
2013-01-10 23:23:07 -06:00
|
|
|
}
|
|
|
|
}
|
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) }
|
2013-05-02 11:28:53 -05:00
|
|
|
_ => { cx.sess.span_bug(e.span, "bad const-slice lit") }
|
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 (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);
|
2013-05-19 00:07:44 -05:00
|
|
|
C_struct([p, sz])
|
2013-01-10 23:23:07 -06:00
|
|
|
}
|
2013-05-02 11:28:53 -05:00
|
|
|
_ => 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-05-18 21:02:45 -05:00
|
|
|
assert_eq!(pth.types.len(), 0);
|
2013-06-13 02:19:50 -05:00
|
|
|
let tcx = cx.tcx;
|
|
|
|
match 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-05-02 11:28:53 -05: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-06-13 02:19:50 -05:00
|
|
|
let tcx = cx.tcx;
|
|
|
|
match 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-06-13 02:19:50 -05:00
|
|
|
let arg_vals = args.map(|a| const_expr(cx, *a));
|
|
|
|
adt::trans_const(cx, repr, 0, arg_vals)
|
2013-02-24 16:38:59 -06:00
|
|
|
}
|
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-06-13 02:19:50 -05:00
|
|
|
let arg_vals = args.map(|a| const_expr(cx, *a));
|
|
|
|
adt::trans_const(cx, repr, vinfo.disr_val, arg_vals)
|
2013-02-24 16:38:59 -06:00
|
|
|
}
|
2013-05-02 11:28:53 -05:00
|
|
|
_ => cx.sess.span_bug(e.span, "expected a struct or variant def")
|
2013-02-24 16:38:59 -06:00
|
|
|
}
|
2013-01-10 23:23:07 -06:00
|
|
|
}
|
|
|
|
ast::expr_paren(e) => { return const_expr(cx, e); }
|
|
|
|
_ => cx.sess.span_bug(e.span,
|
2013-05-02 11:28:53 -05:00
|
|
|
"bad constant expression type in consts::const_expr")
|
2013-01-10 23:23:07 -06:00
|
|
|
};
|
|
|
|
}
|
2012-07-31 20:34:36 -05:00
|
|
|
}
|
|
|
|
|
2013-06-13 02:19:50 -05:00
|
|
|
pub fn trans_const(ccx: @mut 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-05-05 11:17:59 -05:00
|
|
|
let v = ccx.const_values.get_copy(&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
|
|
|
}
|