use crate::context::CodegenCx;
use crate::type_of::LayoutGccExt;
-// TODO
+// TODO(antoyo)
type Funclet = ();
-// TODO: remove this variable.
+// TODO(antoyo): remove this variable.
static mut RETURN_VALUE_COUNT: usize = 0;
enum ExtremumOperation {
let load_ordering =
match order {
- // TODO: does this make sense?
+ // TODO(antoyo): does this make sense?
AtomicOrdering::AcquireRelease | AtomicOrdering::Release => AtomicOrdering::Acquire,
_ => order.clone(),
};
}
fn check_call<'b>(&mut self, _typ: &str, func: Function<'gcc>, args: &'b [RValue<'gcc>]) -> Cow<'b, [RValue<'gcc>]> {
- //let mut fn_ty = self.cx.val_ty(func);
- // Strip off pointers
- /*while self.cx.type_kind(fn_ty) == TypeKind::Pointer {
- fn_ty = self.cx.element_type(fn_ty);
- }*/
-
- /*assert!(
- self.cx.type_kind(fn_ty) == TypeKind::Function,
- "builder::{} not passed a function, but {:?}",
- typ,
- fn_ty
- );
-
- let param_tys = self.cx.func_params_types(fn_ty);
-
- let all_args_match = param_tys
- .iter()
- .zip(args.iter().map(|&v| self.val_ty(v)))
- .all(|(expected_ty, actual_ty)| *expected_ty == actual_ty);*/
-
let mut all_args_match = true;
let mut param_types = vec![];
let param_count = func.get_param_count();
.map(|(_i, (expected_ty, &actual_val))| {
let actual_ty = actual_val.get_type();
if expected_ty != actual_ty {
- /*debug!(
- "type mismatch in function call of {:?}. \
- Expected {:?} for param {}, got {:?}; injecting bitcast",
- func, expected_ty, i, actual_ty
- );*/
- /*println!(
- "type mismatch in function call of {:?}. \
- Expected {:?} for param {}, got {:?}; injecting bitcast",
- func, expected_ty, i, actual_ty
- );*/
self.bitcast(actual_val, expected_ty)
}
else {
}
fn check_ptr_call<'b>(&mut self, _typ: &str, func_ptr: RValue<'gcc>, args: &'b [RValue<'gcc>]) -> Cow<'b, [RValue<'gcc>]> {
- //let mut fn_ty = self.cx.val_ty(func);
- // Strip off pointers
- /*while self.cx.type_kind(fn_ty) == TypeKind::Pointer {
- fn_ty = self.cx.element_type(fn_ty);
- }*/
-
- /*assert!(
- self.cx.type_kind(fn_ty) == TypeKind::Function,
- "builder::{} not passed a function, but {:?}",
- typ,
- fn_ty
- );
-
- let param_tys = self.cx.func_params_types(fn_ty);
-
- let all_args_match = param_tys
- .iter()
- .zip(args.iter().map(|&v| self.val_ty(v)))
- .all(|(expected_ty, actual_ty)| *expected_ty == actual_ty);*/
-
let mut all_args_match = true;
let mut param_types = vec![];
let gcc_func = func_ptr.get_type().is_function_ptr_type().expect("function ptr");
.map(|(_i, (expected_ty, &actual_val))| {
let actual_ty = actual_val.get_type();
if expected_ty != actual_ty {
- /*debug!(
- "type mismatch in function call of {:?}. \
- Expected {:?} for param {}, got {:?}; injecting bitcast",
- func, expected_ty, i, actual_ty
- );*/
- /*println!(
- "type mismatch in function call of {:?}. \
- Expected {:?} for param {}, got {:?}; injecting bitcast",
- func, expected_ty, i, actual_ty
- );*/
self.bitcast(actual_val, expected_ty)
}
else {
}
fn check_store(&mut self, val: RValue<'gcc>, ptr: RValue<'gcc>) -> RValue<'gcc> {
- let dest_ptr_ty = self.cx.val_ty(ptr).make_pointer(); // TODO: make sure make_pointer() is okay here.
+ let dest_ptr_ty = self.cx.val_ty(ptr).make_pointer(); // TODO(antoyo): make sure make_pointer() is okay here.
let stored_ty = self.cx.val_ty(val);
let stored_ptr_ty = self.cx.type_ptr_to(stored_ty);
- //assert_eq!(self.cx.type_kind(dest_ptr_ty), TypeKind::Pointer);
-
if dest_ptr_ty == stored_ptr_ty {
ptr
}
else {
- /*debug!(
- "type mismatch in store. \
- Expected {:?}, got {:?}; inserting bitcast",
- dest_ptr_ty, stored_ptr_ty
- );*/
- /*println!(
- "type mismatch in store. \
- Expected {:?}, got {:?}; inserting bitcast",
- dest_ptr_ty, stored_ptr_ty
- );*/
- //ptr
self.bitcast(ptr, stored_ptr_ty)
}
}
}
fn function_call(&mut self, func: RValue<'gcc>, args: &[RValue<'gcc>], _funclet: Option<&Funclet>) -> RValue<'gcc> {
- //debug!("call {:?} with args ({:?})", func, args);
-
- // TODO: remove when the API supports a different type for functions.
+ // TODO(antoyo): remove when the API supports a different type for functions.
let func: Function<'gcc> = self.cx.rvalue_as_function(func);
let args = self.check_call("call", func, args);
- //let bundle = funclet.map(|funclet| funclet.bundle());
- //let bundle = bundle.as_ref().map(|b| &*b.raw);
// gccjit requires to use the result of functions, even when it's not used.
// That's why we assign the result to a local or call add_eval().
}
fn function_ptr_call(&mut self, func_ptr: RValue<'gcc>, args: &[RValue<'gcc>], _funclet: Option<&Funclet>) -> RValue<'gcc> {
- //debug!("func ptr call {:?} with args ({:?})", func, args);
-
let args = self.check_ptr_call("call", func_ptr, args);
- //let bundle = funclet.map(|funclet| funclet.bundle());
- //let bundle = bundle.as_ref().map(|b| &*b.raw);
// gccjit requires to use the result of functions, even when it's not used.
// That's why we assign the result to a local or call add_eval().
let void_type = self.context.new_type::<()>();
let current_func = current_block.get_function();
- // FIXME: As a temporary workaround for unsupported LLVM intrinsics.
+ // FIXME(antoyo): As a temporary workaround for unsupported LLVM intrinsics.
if gcc_func.get_param_count() == 0 && format!("{:?}", func_ptr) == "__builtin_ia32_pmovmskb128" {
return_type = self.int_type;
}
}
else {
if gcc_func.get_param_count() == 0 {
- // FIXME: As a temporary workaround for unsupported LLVM intrinsics.
+ // FIXME(antoyo): As a temporary workaround for unsupported LLVM intrinsics.
current_block.add_eval(None, self.cx.context.new_call_through_ptr(None, func_ptr, &[]));
}
else {
}
pub fn overflow_call(&mut self, func: Function<'gcc>, args: &[RValue<'gcc>], _funclet: Option<&Funclet>) -> RValue<'gcc> {
- //debug!("overflow_call {:?} with args ({:?})", func, args);
-
- //let bundle = funclet.map(|funclet| funclet.bundle());
- //let bundle = bundle.as_ref().map(|b| &*b.raw);
-
// gccjit requires to use the result of functions, even when it's not used.
// That's why we assign the result to a local.
let return_type = self.context.new_type::<bool>();
let current_block = self.current_block.borrow().expect("block");
let current_func = current_block.get_function();
- // TODO: return the new_call() directly? Since the overflow function has no side-effects.
+ // TODO(antoyo): return the new_call() directly? Since the overflow function has no side-effects.
unsafe { RETURN_VALUE_COUNT += 1 };
let result = current_func.new_local(None, return_type, &format!("returnValue{}", unsafe { RETURN_VALUE_COUNT }));
current_block.add_assignment(None, result, self.cx.context.new_call(None, func, &args));
self.llbb().end_with_conditional(None, condition, then, catch);
self.context.new_rvalue_from_int(self.int_type, 0)
- // TODO
- /*debug!("invoke {:?} with args ({:?})", func, args);
-
- let args = self.check_call("invoke", func, args);
- let bundle = funclet.map(|funclet| funclet.bundle());
- let bundle = bundle.as_ref().map(|b| &*b.raw);
-
- unsafe {
- llvm::LLVMRustBuildInvoke(
- self.llbuilder,
- func,
- args.as_ptr(),
- args.len() as c_uint,
- then,
- catch,
- bundle,
- UNNAMED,
- )
- }*/
+ // TODO(antoyo)
}
fn unreachable(&mut self) {
}
fn add(&mut self, a: RValue<'gcc>, mut b: RValue<'gcc>) -> RValue<'gcc> {
- // FIXME: this should not be required.
+ // FIXME(antoyo): this should not be required.
if format!("{:?}", a.get_type()) != format!("{:?}", b.get_type()) {
b = self.context.new_cast(None, b, a.get_type());
}
}
fn udiv(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
- // TODO: convert the arguments to unsigned?
+ // TODO(antoyo): convert the arguments to unsigned?
a / b
}
fn exactudiv(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
- // TODO: convert the arguments to unsigned?
- // TODO: poison if not exact.
+ // TODO(antoyo): convert the arguments to unsigned?
+ // TODO(antoyo): poison if not exact.
a / b
}
fn sdiv(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
- // TODO: convert the arguments to signed?
+ // TODO(antoyo): convert the arguments to signed?
a / b
}
fn exactsdiv(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
- // TODO: posion if not exact.
- // FIXME: rustc_codegen_ssa::mir::intrinsic uses different types for a and b but they
+ // TODO(antoyo): posion if not exact.
+ // FIXME(antoyo): rustc_codegen_ssa::mir::intrinsic uses different types for a and b but they
// should be the same.
let typ = a.get_type().to_signed(self);
let a = self.context.new_cast(None, a, typ);
fn frem(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
if a.get_type() == self.cx.float_type {
let fmodf = self.context.get_builtin_function("fmodf");
- // FIXME: this seems to produce the wrong result.
+ // FIXME(antoyo): this seems to produce the wrong result.
return self.context.new_call(None, fmodf, &[a, b]);
}
assert_eq!(a.get_type(), self.cx.double_type);
}
fn shl(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
- // FIXME: remove the casts when libgccjit can shift an unsigned number by an unsigned number.
+ // FIXME(antoyo): remove the casts when libgccjit can shift an unsigned number by an unsigned number.
let a_type = a.get_type();
let b_type = b.get_type();
if a_type.is_unsigned(self) && b_type.is_signed(self) {
- //println!("shl: {:?} -> {:?}", a, b_type);
let a = self.context.new_cast(None, a, b_type);
let result = a << b;
- //println!("shl: {:?} -> {:?}", result, a_type);
self.context.new_cast(None, result, a_type)
}
else if a_type.is_signed(self) && b_type.is_unsigned(self) {
- //println!("shl: {:?} -> {:?}", b, a_type);
let b = self.context.new_cast(None, b, a_type);
a << b
}
}
fn lshr(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
- // FIXME: remove the casts when libgccjit can shift an unsigned number by an unsigned number.
- // TODO: cast to unsigned to do a logical shift if that does not work.
+ // FIXME(antoyo): remove the casts when libgccjit can shift an unsigned number by an unsigned number.
+ // TODO(antoyo): cast to unsigned to do a logical shift if that does not work.
let a_type = a.get_type();
let b_type = b.get_type();
if a_type.is_unsigned(self) && b_type.is_signed(self) {
- //println!("lshl: {:?} -> {:?}", a, b_type);
let a = self.context.new_cast(None, a, b_type);
let result = a >> b;
- //println!("lshl: {:?} -> {:?}", result, a_type);
self.context.new_cast(None, result, a_type)
}
else if a_type.is_signed(self) && b_type.is_unsigned(self) {
- //println!("lshl: {:?} -> {:?}", b, a_type);
let b = self.context.new_cast(None, b, a_type);
a >> b
}
}
fn ashr(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
- // TODO: check whether behavior is an arithmetic shift for >> .
- // FIXME: remove the casts when libgccjit can shift an unsigned number by an unsigned number.
+ // TODO(antoyo): check whether behavior is an arithmetic shift for >> .
+ // FIXME(antoyo): remove the casts when libgccjit can shift an unsigned number by an unsigned number.
let a_type = a.get_type();
let b_type = b.get_type();
if a_type.is_unsigned(self) && b_type.is_signed(self) {
- //println!("ashl: {:?} -> {:?}", a, b_type);
let a = self.context.new_cast(None, a, b_type);
let result = a >> b;
- //println!("ashl: {:?} -> {:?}", result, a_type);
self.context.new_cast(None, result, a_type)
}
else if a_type.is_signed(self) && b_type.is_unsigned(self) {
- //println!("ashl: {:?} -> {:?}", b, a_type);
let b = self.context.new_cast(None, b, a_type);
a >> b
}
}
fn and(&mut self, a: RValue<'gcc>, mut b: RValue<'gcc>) -> RValue<'gcc> {
- // FIXME: hack by putting the result in a variable to workaround this bug:
+ // FIXME(antoyo): hack by putting the result in a variable to workaround this bug:
// https://gcc.gnu.org/bugzilla//show_bug.cgi?id=95498
if a.get_type() != b.get_type() {
b = self.context.new_cast(None, b, a.get_type());
}
fn or(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
- // FIXME: hack by putting the result in a variable to workaround this bug:
+ // FIXME(antoyo): hack by putting the result in a variable to workaround this bug:
// https://gcc.gnu.org/bugzilla//show_bug.cgi?id=95498
let res = self.current_func().new_local(None, b.get_type(), "orResult");
self.llbb().add_assignment(None, res, a | b);
}
fn neg(&mut self, a: RValue<'gcc>) -> RValue<'gcc> {
- // TODO: use new_unary_op()?
+ // TODO(antoyo): use new_unary_op()?
self.cx.context.new_rvalue_from_long(a.get_type(), 0) - a
}
}
fn unchecked_usub(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
- // TODO: should generate poison value?
+ // TODO(antoyo): should generate poison value?
a - b
}
fn fadd_fast(&mut self, _lhs: RValue<'gcc>, _rhs: RValue<'gcc>) -> RValue<'gcc> {
unimplemented!();
- /*unsafe {
- let instr = llvm::LLVMBuildFAdd(self.llbuilder, lhs, rhs, UNNAMED);
- llvm::LLVMRustSetHasUnsafeAlgebra(instr);
- instr
- }*/
}
fn fsub_fast(&mut self, _lhs: RValue<'gcc>, _rhs: RValue<'gcc>) -> RValue<'gcc> {
unimplemented!();
- /*unsafe {
- let instr = llvm::LLVMBuildFSub(self.llbuilder, lhs, rhs, UNNAMED);
- llvm::LLVMRustSetHasUnsafeAlgebra(instr);
- instr
- }*/
}
fn fmul_fast(&mut self, _lhs: RValue<'gcc>, _rhs: RValue<'gcc>) -> RValue<'gcc> {
unimplemented!();
- /*unsafe {
- let instr = llvm::LLVMBuildFMul(self.llbuilder, lhs, rhs, UNNAMED);
- llvm::LLVMRustSetHasUnsafeAlgebra(instr);
- instr
- }*/
}
fn fdiv_fast(&mut self, _lhs: RValue<'gcc>, _rhs: RValue<'gcc>) -> RValue<'gcc> {
unimplemented!();
- /*unsafe {
- let instr = llvm::LLVMBuildFDiv(self.llbuilder, lhs, rhs, UNNAMED);
- llvm::LLVMRustSetHasUnsafeAlgebra(instr);
- instr
- }*/
}
fn frem_fast(&mut self, _lhs: RValue<'gcc>, _rhs: RValue<'gcc>) -> RValue<'gcc> {
unimplemented!();
- /*unsafe {
- let instr = llvm::LLVMBuildFRem(self.llbuilder, lhs, rhs, UNNAMED);
- llvm::LLVMRustSetHasUnsafeAlgebra(instr);
- instr
- }*/
}
fn checked_binop(&mut self, oop: OverflowOp, typ: Ty<'_>, lhs: Self::Value, rhs: Self::Value) -> (Self::Value, Self::Value) {
_ => panic!("tried to get overflow intrinsic for op applied to non-int type"),
};
- // TODO: remove duplication with intrinsic?
+ // TODO(antoyo): remove duplication with intrinsic?
let name =
match oop {
OverflowOp::Add =>
let intrinsic = self.context.get_builtin_function(&name);
let res = self.current_func()
- // TODO: is it correct to use rhs type instead of the parameter typ?
+ // TODO(antoyo): is it correct to use rhs type instead of the parameter typ?
.new_local(None, rhs.get_type(), "binopResult")
.get_address(None);
let overflow = self.overflow_call(intrinsic, &[lhs, rhs, res], None);
}
fn alloca(&mut self, ty: Type<'gcc>, align: Align) -> RValue<'gcc> {
- // FIXME: this check that we don't call get_aligned() a second time on a time.
+ // FIXME(antoyo): this check that we don't call get_aligned() a second time on a type.
// Ideally, we shouldn't need to do this check.
let aligned_type =
if ty == self.cx.u128_type || ty == self.cx.i128_type {
else {
ty.get_aligned(align.bytes())
};
- // TODO: It might be better to return a LValue, but fixing the rustc API is non-trivial.
+ // TODO(antoyo): It might be better to return a LValue, but fixing the rustc API is non-trivial.
self.stack_var_count.set(self.stack_var_count.get() + 1);
self.current_func().new_local(None, aligned_type, &format!("stack_var_{}", self.stack_var_count.get())).get_address(None)
}
fn dynamic_alloca(&mut self, _ty: Type<'gcc>, _align: Align) -> RValue<'gcc> {
unimplemented!();
- /*unsafe {
- let alloca = llvm::LLVMBuildAlloca(self.llbuilder, ty, UNNAMED);
- llvm::LLVMSetAlignment(alloca, align.bytes() as c_uint);
- alloca
- }*/
}
fn array_alloca(&mut self, _ty: Type<'gcc>, _len: RValue<'gcc>, _align: Align) -> RValue<'gcc> {
unimplemented!();
- /*unsafe {
- let alloca = llvm::LLVMBuildArrayAlloca(self.llbuilder, ty, len, UNNAMED);
- llvm::LLVMSetAlignment(alloca, align.bytes() as c_uint);
- alloca
- }*/
}
fn load(&mut self, _ty: Type<'gcc>, ptr: RValue<'gcc>, _align: Align) -> RValue<'gcc> {
- // TODO: use ty.
+ // TODO(antoyo): use ty.
let block = self.llbb();
let function = block.get_function();
// NOTE: instead of returning the dereference here, we have to assign it to a variable in
// the current basic block. Otherwise, it could be used in another basic block, causing a
// dereference after a drop, for instance.
- // TODO: handle align.
+ // TODO(antoyo): handle align.
let deref = ptr.dereference(None).to_rvalue();
let value_type = deref.get_type();
unsafe { RETURN_VALUE_COUNT += 1 };
}
fn volatile_load(&mut self, _ty: Type<'gcc>, ptr: RValue<'gcc>) -> RValue<'gcc> {
- // TODO: use ty.
- //println!("5: volatile load: {:?} to {:?}", ptr, ptr.get_type().make_volatile());
+ // TODO(antoyo): use ty.
let ptr = self.context.new_cast(None, ptr, ptr.get_type().make_volatile());
- //println!("6");
ptr.dereference(None).to_rvalue()
}
fn atomic_load(&mut self, _ty: Type<'gcc>, ptr: RValue<'gcc>, order: AtomicOrdering, size: Size) -> RValue<'gcc> {
- // TODO: use ty.
- // TODO: handle alignment.
+ // TODO(antoyo): use ty.
+ // TODO(antoyo): handle alignment.
let atomic_load = self.context.get_builtin_function(&format!("__atomic_load_{}", size.bytes()));
let ordering = self.context.new_rvalue_from_int(self.i32_type, order.to_gcc());
}
fn load_operand(&mut self, place: PlaceRef<'tcx, RValue<'gcc>>) -> OperandRef<'tcx, RValue<'gcc>> {
- //debug!("PlaceRef::load: {:?}", place);
-
assert_eq!(place.llextra.is_some(), place.layout.is_unsized());
if place.layout.is_zst() {
OperandValue::Ref(place.llval, Some(llextra), place.align)
}
else if place.layout.is_gcc_immediate() {
- let const_llval = None;
- /*unsafe {
- if let Some(global) = llvm::LLVMIsAGlobalVariable(place.llval) {
- if llvm::LLVMIsGlobalConstant(global) == llvm::True {
- const_llval = llvm::LLVMGetInitializer(global);
- }
- }
- }*/
- let llval = const_llval.unwrap_or_else(|| {
- let load = self.load(place.llval.get_type(), place.llval, place.align);
- if let abi::Abi::Scalar(ref scalar) = place.layout.abi {
- scalar_load_metadata(self, load, scalar);
- }
- load
- });
- OperandValue::Immediate(self.to_immediate(llval, place.layout))
+ let load = self.load(place.llval.get_type(), place.llval, place.align);
+ if let abi::Abi::Scalar(ref scalar) = place.layout.abi {
+ scalar_load_metadata(self, load, scalar);
+ }
+ OperandValue::Immediate(self.to_immediate(load, place.layout))
}
else if let abi::Abi::ScalarPair(ref a, ref b) = place.layout.abi {
let b_offset = a.value.size(self).align_to(b.value.align(self).abi);
}
fn range_metadata(&mut self, _load: RValue<'gcc>, _range: Range<u128>) {
- // TODO
- /*if self.sess().target.target.arch == "amdgpu" {
- // amdgpu/LLVM does something weird and thinks a i64 value is
- // split into a v2i32, halving the bitwidth LLVM expects,
- // tripping an assertion. So, for now, just disable this
- // optimization.
- return;
- }
-
- unsafe {
- let llty = self.cx.val_ty(load);
- let v = [
- self.cx.const_uint_big(llty, range.start),
- self.cx.const_uint_big(llty, range.end),
- ];
-
- llvm::LLVMSetMetadata(
- load,
- llvm::MD_range as c_uint,
- llvm::LLVMMDNodeInContext(self.cx.llcx, v.as_ptr(), v.len() as c_uint),
- );
- }*/
+ // TODO(antoyo)
}
fn nonnull_metadata(&mut self, _load: RValue<'gcc>) {
- // TODO
- /*unsafe {
- llvm::LLVMSetMetadata(
- load,
- llvm::MD_nonnull as c_uint,
- llvm::LLVMMDNodeInContext(self.cx.llcx, ptr::null(), 0),
- );
- }*/
+ // TODO(antoyo)
}
fn store(&mut self, val: RValue<'gcc>, ptr: RValue<'gcc>, align: Align) -> RValue<'gcc> {
}
fn store_with_flags(&mut self, val: RValue<'gcc>, ptr: RValue<'gcc>, _align: Align, _flags: MemFlags) -> RValue<'gcc> {
- //debug!("Store {:?} -> {:?} ({:?})", val, ptr, flags);
let ptr = self.check_store(val, ptr);
self.llbb().add_assignment(None, ptr.dereference(None), val);
- /*let align =
- if flags.contains(MemFlags::UNALIGNED) { 1 } else { align.bytes() as c_uint };
- llvm::LLVMSetAlignment(store, align);
- if flags.contains(MemFlags::VOLATILE) {
- llvm::LLVMSetVolatile(store, llvm::True);
- }
- if flags.contains(MemFlags::NONTEMPORAL) {
- // According to LLVM [1] building a nontemporal store must
- // *always* point to a metadata value of the integer 1.
- //
- // [1]: http://llvm.org/docs/LangRef.html#store-instruction
- let one = self.cx.const_i32(1);
- let node = llvm::LLVMMDNodeInContext(self.cx.llcx, &one, 1);
- llvm::LLVMSetMetadata(store, llvm::MD_nontemporal as c_uint, node);
- }*/
- // NOTE: dummy value here since it's never used. FIXME: API should not return a value here?
+ // TODO(antoyo): handle align and flags.
+ // NOTE: dummy value here since it's never used. FIXME(antoyo): API should not return a value here?
self.cx.context.new_rvalue_zero(self.type_i32())
}
fn atomic_store(&mut self, value: RValue<'gcc>, ptr: RValue<'gcc>, order: AtomicOrdering, size: Size) {
- // TODO: handle alignment.
+ // TODO(antoyo): handle alignment.
let atomic_store = self.context.get_builtin_function(&format!("__atomic_store_{}", size.bytes()));
let ordering = self.context.new_rvalue_from_int(self.i32_type, order.to_gcc());
let volatile_const_void_ptr_type = self.context.new_type::<*mut ()>().make_const().make_volatile();
let ptr = self.context.new_cast(None, ptr, volatile_const_void_ptr_type);
- // FIXME: fix libgccjit to allow comparing an integer type with an aligned integer type because
+ // FIXME(antoyo): fix libgccjit to allow comparing an integer type with an aligned integer type because
// the following cast is required to avoid this error:
// gcc_jit_context_new_call: mismatching types for argument 2 of function "__atomic_store_4": assignment to param arg1 (type: int) from loadedValue3577 (type: unsigned int __attribute__((aligned(4))))
let int_type = atomic_store.get_param(1).to_rvalue().get_type();
}
fn inbounds_gep(&mut self, _typ: Type<'gcc>, ptr: RValue<'gcc>, indices: &[RValue<'gcc>]) -> RValue<'gcc> {
- // FIXME: would be safer if doing the same thing (loop) as gep.
- // TODO: specify inbounds somehow.
+ // FIXME(antoyo): would be safer if doing the same thing (loop) as gep.
+ // TODO(antoyo): specify inbounds somehow.
match indices.len() {
1 => {
self.context.new_array_access(None, ptr, indices[0]).get_address(None)
},
2 => {
- let array = ptr.dereference(None); // TODO: assert that first index is 0?
+ let array = ptr.dereference(None); // TODO(antoyo): assert that first index is 0?
self.context.new_array_access(None, array, indices[1]).get_address(None)
},
_ => unimplemented!(),
}
fn struct_gep(&mut self, value_type: Type<'gcc>, ptr: RValue<'gcc>, idx: u64) -> RValue<'gcc> {
- // FIXME: it would be better if the API only called this on struct, not on arrays.
+ // FIXME(antoyo): it would be better if the API only called this on struct, not on arrays.
assert_eq!(idx as usize as u64, idx);
let value = ptr.dereference(None).to_rvalue();
/* Casts */
fn trunc(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> {
- // TODO: check that it indeed truncate the value.
- //println!("trunc: {:?} -> {:?}", value, dest_ty);
+ // TODO(antoyo): check that it indeed truncate the value.
self.context.new_cast(None, value, dest_ty)
}
fn sext(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> {
- // TODO: check that it indeed sign extend the value.
- //println!("Sext {:?} to {:?}", value, dest_ty);
- //if let Some(vector_type) = value.get_type().is_vector() {
+ // TODO(antoyo): check that it indeed sign extend the value.
if dest_ty.is_vector().is_some() {
- // TODO: nothing to do as it is only for LLVM?
+ // TODO(antoyo): nothing to do as it is only for LLVM?
return value;
- /*let dest_type = self.context.new_vector_type(dest_ty, vector_type.get_num_units() as u64);
- println!("Casting {:?} to {:?}", value, dest_type);
- return self.context.new_cast(None, value, dest_type);*/
}
self.context.new_cast(None, value, dest_ty)
}
fn fptoui(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> {
- //println!("7: fptoui: {:?} to {:?}", value, dest_ty);
- let ret = self.context.new_cast(None, value, dest_ty);
- //println!("8");
- ret
- //unsafe { llvm::LLVMBuildFPToUI(self.llbuilder, val, dest_ty, UNNAMED) }
+ self.context.new_cast(None, value, dest_ty)
}
fn fptosi(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> {
}
fn uitofp(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> {
- //println!("1: uitofp: {:?} -> {:?}", value, dest_ty);
- let ret = self.context.new_cast(None, value, dest_ty);
- //println!("2");
- ret
+ self.context.new_cast(None, value, dest_ty)
}
fn sitofp(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> {
- //println!("3: sitofp: {:?} -> {:?}", value, dest_ty);
- let ret = self.context.new_cast(None, value, dest_ty);
- //println!("4");
- ret
+ self.context.new_cast(None, value, dest_ty)
}
fn fptrunc(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> {
- // TODO: make sure it trancates.
+ // TODO(antoyo): make sure it truncates.
self.context.new_cast(None, value, dest_ty)
}
fn intcast(&mut self, value: RValue<'gcc>, dest_typ: Type<'gcc>, _is_signed: bool) -> RValue<'gcc> {
// NOTE: is_signed is for value, not dest_typ.
- //println!("intcast: {:?} ({:?}) -> {:?}", value, value.get_type(), dest_typ);
self.cx.context.new_cast(None, value, dest_typ)
}
fn pointercast(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> {
- //println!("pointercast: {:?} ({:?}) -> {:?}", value, value.get_type(), dest_ty);
let val_type = value.get_type();
match (type_is_pointer(val_type), type_is_pointer(dest_ty)) {
(false, true) => {
},
(false, false) => {
// When they are not pointers, we want a transmute (or reinterpret_cast).
- //self.cx.context.new_cast(None, value, dest_ty)
self.bitcast(value, dest_ty)
},
(true, true) => self.cx.context.new_cast(None, value, dest_ty),
let src = self.pointercast(src, self.type_ptr_to(self.type_void()));
let memcpy = self.context.get_builtin_function("memcpy");
let block = self.block.expect("block");
- // TODO: handle aligns and is_volatile.
+ // TODO(antoyo): handle aligns and is_volatile.
block.add_eval(None, self.context.new_call(None, memcpy, &[dst, src, size]));
}
let memmove = self.context.get_builtin_function("memmove");
let block = self.block.expect("block");
- // TODO: handle is_volatile.
+ // TODO(antoyo): handle is_volatile.
block.add_eval(None, self.context.new_call(None, memmove, &[dst, src, size]));
}
let ptr = self.pointercast(ptr, self.type_i8p());
let memset = self.context.get_builtin_function("memset");
let block = self.block.expect("block");
- // TODO: handle aligns and is_volatile.
- //println!("memset: {:?} -> {:?}", fill_byte, self.i32_type);
+ // TODO(antoyo): handle align and is_volatile.
let fill_byte = self.context.new_cast(None, fill_byte, self.i32_type);
let size = self.intcast(size, self.type_size_t(), false);
block.add_eval(None, self.context.new_call(None, memset, &[ptr, fill_byte, size]));
#[allow(dead_code)]
fn va_arg(&mut self, _list: RValue<'gcc>, _ty: Type<'gcc>) -> RValue<'gcc> {
unimplemented!();
- //unsafe { llvm::LLVMBuildVAArg(self.llbuilder, list, ty, UNNAMED) }
}
fn extract_element(&mut self, _vec: RValue<'gcc>, _idx: RValue<'gcc>) -> RValue<'gcc> {
unimplemented!();
- //unsafe { llvm::LLVMBuildExtractElement(self.llbuilder, vec, idx, UNNAMED) }
}
fn vector_splat(&mut self, _num_elts: usize, _elt: RValue<'gcc>) -> RValue<'gcc> {
unimplemented!();
- /*unsafe {
- let elt_ty = self.cx.val_ty(elt);
- let undef = llvm::LLVMGetUndef(self.type_vector(elt_ty, num_elts as u64));
- let vec = self.insert_element(undef, elt, self.cx.const_i32(0));
- let vec_i32_ty = self.type_vector(self.type_i32(), num_elts as u64);
- self.shuffle_vector(vec, undef, self.const_null(vec_i32_ty))
- }*/
}
fn extract_value(&mut self, aggregate_value: RValue<'gcc>, idx: u64) -> RValue<'gcc> {
- // FIXME: it would be better if the API only called this on struct, not on arrays.
+ // FIXME(antoyo): it would be better if the API only called this on struct, not on arrays.
assert_eq!(idx as usize as u64, idx);
let value_type = aggregate_value.get_type();
else {
panic!("Unexpected type {:?}", value_type);
}
- /*assert_eq!(idx as c_uint as u64, idx);
- unsafe { llvm::LLVMBuildExtractValue(self.llbuilder, agg_val, idx as c_uint, UNNAMED) }*/
}
fn insert_value(&mut self, aggregate_value: RValue<'gcc>, value: RValue<'gcc>, idx: u64) -> RValue<'gcc> {
- // FIXME: it would be better if the API only called this on struct, not on arrays.
+ // FIXME(antoyo): it would be better if the API only called this on struct, not on arrays.
assert_eq!(idx as usize as u64, idx);
let value_type = aggregate_value.get_type();
let struct_type = self.context.new_struct_type(None, "landing_pad", &[field1, field2]);
self.current_func().new_local(None, struct_type.as_type(), "landing_pad")
.to_rvalue()
- // TODO
- /*unsafe {
- llvm::LLVMBuildLandingPad(self.llbuilder, ty, pers_fn, num_clauses as c_uint, UNNAMED)
- }*/
+ // TODO(antoyo): Properly implement unwinding.
+ // the above is just to make the compilation work as it seems
+ // rustc_codegen_ssa now calls the unwinding builder methods even on panic=abort.
}
fn set_cleanup(&mut self, _landing_pad: RValue<'gcc>) {
- // TODO
- /*unsafe {
- llvm::LLVMSetCleanup(landing_pad, llvm::True);
- }*/
+ // TODO(antoyo)
}
fn resume(&mut self, _exn: RValue<'gcc>) -> RValue<'gcc> {
unimplemented!();
- //unsafe { llvm::LLVMBuildResume(self.llbuilder, exn) }
}
fn cleanup_pad(&mut self, _parent: Option<RValue<'gcc>>, _args: &[RValue<'gcc>]) -> Funclet {
unimplemented!();
- /*let name = const_cstr!("cleanuppad");
- let ret = unsafe {
- llvm::LLVMRustBuildCleanupPad(
- self.llbuilder,
- parent,
- args.len() as c_uint,
- args.as_ptr(),
- name.as_ptr(),
- )
- };
- Funclet::new(ret.expect("LLVM does not have support for cleanuppad"))*/
}
fn cleanup_ret(&mut self, _funclet: &Funclet, _unwind: Option<Block<'gcc>>) -> RValue<'gcc> {
unimplemented!();
- /*let ret =
- unsafe { llvm::LLVMRustBuildCleanupRet(self.llbuilder, funclet.cleanuppad(), unwind) };
- ret.expect("LLVM does not have support for cleanupret")*/
}
fn catch_pad(&mut self, _parent: RValue<'gcc>, _args: &[RValue<'gcc>]) -> Funclet {
unimplemented!();
- /*let name = const_cstr!("catchpad");
- let ret = unsafe {
- llvm::LLVMRustBuildCatchPad(
- self.llbuilder,
- parent,
- args.len() as c_uint,
- args.as_ptr(),
- name.as_ptr(),
- )
- };
- Funclet::new(ret.expect("LLVM does not have support for catchpad"))*/
}
fn catch_switch(&mut self, _parent: Option<RValue<'gcc>>, _unwind: Option<Block<'gcc>>, _num_handlers: usize) -> RValue<'gcc> {
unimplemented!();
- /*let name = const_cstr!("catchswitch");
- let ret = unsafe {
- llvm::LLVMRustBuildCatchSwitch(
- self.llbuilder,
- parent,
- unwind,
- num_handlers as c_uint,
- name.as_ptr(),
- )
- };
- ret.expect("LLVM does not have support for catchswitch")*/
}
fn add_handler(&mut self, _catch_switch: RValue<'gcc>, _handler: Block<'gcc>) {
unimplemented!();
- /*unsafe {
- llvm::LLVMRustAddHandler(catch_switch, handler);
- }*/
}
fn set_personality_fn(&mut self, _personality: RValue<'gcc>) {
- // TODO
- /*unsafe {
- llvm::LLVMSetPersonalityFn(self.llfn(), personality);
- }*/
+ // TODO(antoyo)
}
// Atomic Operations
let pair_type = self.cx.type_struct(&[src.get_type(), self.bool_type], false);
let result = self.current_func().new_local(None, pair_type, "atomic_cmpxchg_result");
- let align = Align::from_bits(64).expect("align"); // TODO: use good align.
+ let align = Align::from_bits(64).expect("align"); // TODO(antoyo): use good align.
let value_type = result.to_rvalue().get_type();
if let Some(struct_type) = value_type.is_struct() {
// expected so that we store expected after the call.
self.store(expected.to_rvalue(), result.access_field(None, struct_type.get_field(0)).get_address(None), align);
}
- // TODO: handle when value is not a struct.
+ // TODO(antoyo): handle when value is not a struct.
result.to_rvalue()
}
let void_ptr_type = self.context.new_type::<*mut ()>();
let volatile_void_ptr_type = void_ptr_type.make_volatile();
let dst = self.context.new_cast(None, dst, volatile_void_ptr_type);
- // NOTE: not sure why, but we have the wrong type here.
+ // FIXME(antoyo): not sure why, but we have the wrong type here.
let new_src_type = atomic_function.get_param(1).to_rvalue().get_type();
let src = self.context.new_cast(None, src, new_src_type);
let res = self.context.new_call(None, atomic_function, &[dst, src, order]);
fn set_invariant_load(&mut self, load: RValue<'gcc>) {
// NOTE: Hack to consider vtable function pointer as non-global-variable function pointer.
self.normal_function_addresses.borrow_mut().insert(load);
- // TODO
- /*unsafe {
- llvm::LLVMSetMetadata(
- load,
- llvm::MD_invariant_load as c_uint,
- llvm::LLVMMDNodeInContext(self.cx.llcx, ptr::null(), 0),
- );
- }*/
+ // TODO(antoyo)
}
fn lifetime_start(&mut self, _ptr: RValue<'gcc>, _size: Size) {
- // TODO
- //self.call_lifetime_intrinsic("llvm.lifetime.start.p0i8", ptr, size);
+ // TODO(antoyo)
}
fn lifetime_end(&mut self, _ptr: RValue<'gcc>, _size: Size) {
- // TODO
- //self.call_lifetime_intrinsic("llvm.lifetime.end.p0i8", ptr, size);
+ // TODO(antoyo)
}
fn call(&mut self, _typ: Type<'gcc>, func: RValue<'gcc>, args: &[RValue<'gcc>], funclet: Option<&Funclet>) -> RValue<'gcc> {
- // FIXME: remove when having a proper API.
+ // FIXME(antoyo): remove when having a proper API.
let gcc_func = unsafe { std::mem::transmute(func) };
if self.functions.borrow().values().find(|value| **value == gcc_func).is_some() {
self.function_call(func, args, funclet)
}
fn zext(&mut self, value: RValue<'gcc>, dest_typ: Type<'gcc>) -> RValue<'gcc> {
- // FIXME: this does not zero-extend.
+ // FIXME(antoyo): this does not zero-extend.
if value.get_type().is_bool() && dest_typ.is_i8(&self.cx) {
- // FIXME: hack because base::from_immediate converts i1 to i8.
+ // FIXME(antoyo): hack because base::from_immediate converts i1 to i8.
// Fix the code in codegen_ssa::base::from_immediate.
return value;
}
- //println!("zext: {:?} -> {:?}", value, dest_typ);
self.context.new_cast(None, value, dest_typ)
}
fn do_not_inline(&mut self, _llret: RValue<'gcc>) {
unimplemented!();
- //llvm::Attribute::NoInline.apply_callsite(llvm::AttributePlace::Function, llret);
}
fn set_span(&mut self, _span: Span) {}
fn instrprof_increment(&mut self, _fn_name: RValue<'gcc>, _hash: RValue<'gcc>, _num_counters: RValue<'gcc>, _index: RValue<'gcc>) {
unimplemented!();
- /*debug!(
- "instrprof_increment() with args ({:?}, {:?}, {:?}, {:?})",
- fn_name, hash, num_counters, index
- );
-
- let llfn = unsafe { llvm::LLVMRustGetInstrProfIncrementIntrinsic(self.cx().llmod) };
- let args = &[fn_name, hash, num_counters, index];
- let args = self.check_call("call", llfn, args);
-
- unsafe {
- let _ = llvm::LLVMRustBuildCall(
- self.llbuilder,
- llfn,
- args.as_ptr() as *const &llvm::Value,
- args.len() as c_uint,
- None,
- );
- }*/
}
}
impl ToGccComp for RealPredicate {
fn to_gcc_comparison(&self) -> ComparisonOp {
- // TODO: check that ordered vs non-ordered is respected.
+ // TODO(antoyo): check that ordered vs non-ordered is respected.
match *self {
RealPredicate::RealPredicateFalse => unreachable!(),
RealPredicate::RealOEQ => ComparisonOp::Equals,
let ordering =
match self {
- AtomicOrdering::NotAtomic => __ATOMIC_RELAXED, // TODO: check if that's the same.
+ AtomicOrdering::NotAtomic => __ATOMIC_RELAXED, // TODO(antoyo): check if that's the same.
AtomicOrdering::Unordered => __ATOMIC_RELAXED,
- AtomicOrdering::Monotonic => __ATOMIC_RELAXED, // TODO: check if that's the same.
+ AtomicOrdering::Monotonic => __ATOMIC_RELAXED, // TODO(antoyo): check if that's the same.
AtomicOrdering::Acquire => __ATOMIC_ACQUIRE,
AtomicOrdering::Release => __ATOMIC_RELEASE,
AtomicOrdering::AcquireRelease => __ATOMIC_ACQ_REL,