diff options
| author | antoyo <antoyo@users.noreply.github.com> | 2024-02-28 16:59:16 -0500 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-02-28 16:59:16 -0500 |
| commit | 6ec50107e6f9307ba88c1a4ac2d395c0bb17bc4f (patch) | |
| tree | 0dfb612cf68b3b860f7757a513ce9b2e62f2dbdd /src | |
| parent | 64fc2139267ee3ec5064c5788b279cd95a33c6f6 (diff) | |
| parent | 7c3565e569bb5017baad3a2a708dcdf7c1822d82 (diff) | |
| download | rust-6ec50107e6f9307ba88c1a4ac2d395c0bb17bc4f.tar.gz rust-6ec50107e6f9307ba88c1a4ac2d395c0bb17bc4f.zip | |
Merge pull request #455 from tempdragon/master
feat(debuginfo): Add support for debuginfo, without scope support
Diffstat (limited to 'src')
| -rw-r--r-- | src/base.rs | 2 | ||||
| -rw-r--r-- | src/builder.rs | 407 | ||||
| -rw-r--r-- | src/context.rs | 4 | ||||
| -rw-r--r-- | src/debuginfo.rs | 252 | ||||
| -rw-r--r-- | src/int.rs | 214 | ||||
| -rw-r--r-- | src/intrinsic/mod.rs | 108 | ||||
| -rw-r--r-- | src/lib.rs | 1 |
7 files changed, 602 insertions, 386 deletions
diff --git a/src/base.rs b/src/base.rs index 773e234150d..b1d0f541702 100644 --- a/src/base.rs +++ b/src/base.rs @@ -152,14 +152,12 @@ pub fn compile_codegen_unit(tcx: TyCtxt<'_>, cgu_name: Symbol, target_info: Lock if env::var("CG_GCCJIT_DUMP_GIMPLE").as_deref() == Ok("1") { context.set_dump_initial_gimple(true); } - context.set_debug_info(true); if env::var("CG_GCCJIT_DUMP_EVERYTHING").as_deref() == Ok("1") { context.set_dump_everything(true); } if env::var("CG_GCCJIT_KEEP_INTERMEDIATES").as_deref() == Ok("1") { context.set_keep_intermediates(true); } - if env::var("CG_GCCJIT_VERBOSE").as_deref() == Ok("1") { context.add_driver_option("-v"); } diff --git a/src/builder.rs b/src/builder.rs index 56d9fd30bf6..dcac066f395 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -4,16 +4,7 @@ use std::convert::TryFrom; use std::ops::Deref; use gccjit::{ - BinaryOp, - Block, - ComparisonOp, - Context, - Function, - LValue, - RValue, - ToRValue, - Type, - UnaryOp, + BinaryOp, Block, ComparisonOp, Context, Function, LValue, Location, RValue, ToRValue, Type, UnaryOp }; use rustc_apfloat::{ieee, Float, Round, Status}; use rustc_codegen_ssa::MemFlags; @@ -70,6 +61,7 @@ pub struct Builder<'a: 'gcc, 'gcc, 'tcx> { pub cx: &'a CodegenCx<'gcc, 'tcx>, pub block: Block<'gcc>, stack_var_count: Cell<usize>, + pub loc: Option<Location<'gcc>>, } impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { @@ -78,6 +70,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { cx, block, stack_var_count: Cell::new(0), + loc: None } } @@ -93,14 +86,14 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { _ => order, }; let previous_value = self.atomic_load(dst.get_type(), dst, load_ordering, Size::from_bytes(size)); - let previous_var = func.new_local(None, previous_value.get_type(), "previous_value"); - let return_value = func.new_local(None, previous_value.get_type(), "return_value"); - self.llbb().add_assignment(None, previous_var, previous_value); - self.llbb().add_assignment(None, return_value, previous_var.to_rvalue()); + let previous_var = func.new_local(self.loc, previous_value.get_type(), "previous_value"); + let return_value = func.new_local(self.loc, previous_value.get_type(), "return_value"); + self.llbb().add_assignment(self.loc, previous_var, previous_value); + self.llbb().add_assignment(self.loc, return_value, previous_var.to_rvalue()); let while_block = func.new_block("while"); let after_block = func.new_block("after_while"); - self.llbb().end_with_jump(None, while_block); + self.llbb().end_with_jump(self.loc, while_block); // NOTE: since jumps were added and compare_exchange doesn't expect this, the current block in the // state need to be updated. @@ -112,12 +105,12 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { ExtremumOperation::Min => ComparisonOp::GreaterThan, }; - let cond1 = self.context.new_comparison(None, comparison_operator, previous_var.to_rvalue(), self.context.new_cast(None, src, previous_value.get_type())); + let cond1 = self.context.new_comparison(self.loc, comparison_operator, previous_var.to_rvalue(), self.context.new_cast(self.loc, src, previous_value.get_type())); let compare_exchange = self.compare_exchange(dst, previous_var, src, order, load_ordering, false); - let cond2 = self.cx.context.new_unary_op(None, UnaryOp::LogicalNegate, compare_exchange.get_type(), compare_exchange); - let cond = self.cx.context.new_binary_op(None, BinaryOp::LogicalAnd, self.cx.bool_type, cond1, cond2); + let cond2 = self.cx.context.new_unary_op(self.loc, UnaryOp::LogicalNegate, compare_exchange.get_type(), compare_exchange); + let cond = self.cx.context.new_binary_op(self.loc, BinaryOp::LogicalAnd, self.cx.bool_type, cond1, cond2); - while_block.end_with_conditional(None, cond, while_block, after_block); + while_block.end_with_conditional(self.loc, cond, while_block, after_block); // NOTE: since jumps were added in a place rustc does not expect, the current block in the // state need to be updated. @@ -135,17 +128,17 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { 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); - let expected = self.context.new_cast(None, cmp.get_address(None), void_ptr_type); + let dst = self.context.new_cast(self.loc, dst, volatile_void_ptr_type); + let expected = self.context.new_cast(self.loc, cmp.get_address(self.loc), void_ptr_type); // NOTE: not sure why, but we have the wrong type here. let int_type = compare_exchange.get_param(2).to_rvalue().get_type(); - let src = self.context.new_cast(None, src, int_type); - self.context.new_call(None, compare_exchange, &[dst, expected, src, weak, order, failure_order]) + let src = self.context.new_cast(self.loc, src, int_type); + self.context.new_call(self.loc, compare_exchange, &[dst, expected, src, weak, order, failure_order]) } pub fn assign(&self, lvalue: LValue<'gcc>, value: RValue<'gcc>) { - self.llbb().add_assignment(None, lvalue, value); + self.llbb().add_assignment(self.loc, lvalue, value); } fn check_call<'b>(&mut self, _typ: &str, func: Function<'gcc>, args: &'b [RValue<'gcc>]) -> Cow<'b, [RValue<'gcc>]> { @@ -220,10 +213,10 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let actual_ty = actual_val.get_type(); if expected_ty != actual_ty { if !actual_ty.is_vector() && !expected_ty.is_vector() && (actual_ty.is_integral() && expected_ty.is_integral()) || (actual_ty.get_pointee().is_some() && expected_ty.get_pointee().is_some()) { - self.context.new_cast(None, actual_val, expected_ty) + self.context.new_cast(self.loc, actual_val, expected_ty) } else if on_stack_param_indices.contains(&index) { - actual_val.dereference(None).to_rvalue() + actual_val.dereference(self.loc).to_rvalue() } else { assert!(!((actual_ty.is_vector() && !expected_ty.is_vector()) || (!actual_ty.is_vector() && expected_ty.is_vector())), "{:?} ({}) -> {:?} ({}), index: {:?}[{}]", actual_ty, actual_ty.is_vector(), expected_ty, expected_ty.is_vector(), func_ptr, index); @@ -268,12 +261,12 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let current_func = self.block.get_function(); if return_type != void_type { unsafe { RETURN_VALUE_COUNT += 1 }; - let result = current_func.new_local(None, return_type, &format!("returnValue{}", unsafe { RETURN_VALUE_COUNT })); - self.block.add_assignment(None, result, self.cx.context.new_call(None, func, &args)); + let result = current_func.new_local(self.loc, return_type, &format!("returnValue{}", unsafe { RETURN_VALUE_COUNT })); + self.block.add_assignment(self.loc, result, self.cx.context.new_call(self.loc, func, &args)); result.to_rvalue() } else { - self.block.add_eval(None, self.cx.context.new_call(None, func, &args)); + self.block.add_eval(self.loc, self.cx.context.new_call(self.loc, func, &args)); // Return dummy value when not having return value. self.context.new_rvalue_from_long(self.isize_type, 0) } @@ -286,7 +279,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { None => { // NOTE: due to opaque pointers now being used, we need to cast here. let new_func_type = typ.dyncast_function_ptr_type().expect("function ptr"); - func_ptr = self.context.new_cast(None, func_ptr, typ); + func_ptr = self.context.new_cast(self.loc, func_ptr, typ); new_func_type }, }; @@ -309,26 +302,26 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { if return_type != void_type { unsafe { RETURN_VALUE_COUNT += 1 }; - let return_value = self.cx.context.new_call_through_ptr(None, func_ptr, &args); + let return_value = self.cx.context.new_call_through_ptr(self.loc, func_ptr, &args); let return_value = llvm::adjust_intrinsic_return_value(&self, return_value, &func_name, &args, args_adjusted, orig_args); - let result = current_func.new_local(None, return_value.get_type(), &format!("ptrReturnValue{}", unsafe { RETURN_VALUE_COUNT })); - self.block.add_assignment(None, result, return_value); + let result = current_func.new_local(self.loc, return_value.get_type(), &format!("ptrReturnValue{}", unsafe { RETURN_VALUE_COUNT })); + self.block.add_assignment(self.loc, result, return_value); result.to_rvalue() } else { #[cfg(not(feature="master"))] if gcc_func.get_param_count() == 0 { // FIXME(antoyo): As a temporary workaround for unsupported LLVM intrinsics. - self.block.add_eval(None, self.cx.context.new_call_through_ptr(None, func_ptr, &[])); + self.block.add_eval(self.loc, self.cx.context.new_call_through_ptr(self.loc, func_ptr, &[])); } else { - self.block.add_eval(None, self.cx.context.new_call_through_ptr(None, func_ptr, &args)); + self.block.add_eval(self.loc, self.cx.context.new_call_through_ptr(self.loc, func_ptr, &args)); } #[cfg(feature="master")] - self.block.add_eval(None, self.cx.context.new_call_through_ptr(None, func_ptr, &args)); + self.block.add_eval(self.loc, self.cx.context.new_call_through_ptr(self.loc, func_ptr, &args)); // Return dummy value when not having return value. - let result = current_func.new_local(None, self.isize_type, "dummyValueThatShouldNeverBeUsed"); - self.block.add_assignment(None, result, self.context.new_rvalue_from_long(self.isize_type, 0)); + let result = current_func.new_local(self.loc, self.isize_type, "dummyValueThatShouldNeverBeUsed"); + self.block.add_assignment(self.loc, result, self.context.new_rvalue_from_long(self.isize_type, 0)); result.to_rvalue() } } @@ -340,8 +333,8 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let current_func = self.block.get_function(); // 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!("overflowReturnValue{}", unsafe { RETURN_VALUE_COUNT })); - self.block.add_assignment(None, result, self.cx.context.new_call(None, func, &args)); + let result = current_func.new_local(self.loc, return_type, &format!("overflowReturnValue{}", unsafe { RETURN_VALUE_COUNT })); + self.block.add_assignment(self.loc, result, self.cx.context.new_call(self.loc, func, &args)); result.to_rvalue() } } @@ -405,6 +398,15 @@ impl<'gcc, 'tcx> BackendTypes for Builder<'_, 'gcc, 'tcx> { type DIVariable = <CodegenCx<'gcc, 'tcx> as BackendTypes>::DIVariable; } +pub fn set_rval_location<'a, 'gcc, 'tcx>(bx: &mut Builder<'a,'gcc,'tcx>, rvalue:RValue<'gcc>) -> RValue<'gcc> { + if bx.loc.is_some(){ + #[cfg(feature = "master")] + rvalue.set_location(bx.loc.unwrap()); + } + rvalue + +} + impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { fn build(cx: &'a CodegenCx<'gcc, 'tcx>, block: Block<'gcc>) -> Builder<'a, 'gcc, 'tcx> { Builder::with_cx(cx, block) @@ -429,29 +431,29 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { } fn ret_void(&mut self) { - self.llbb().end_with_void_return(None) + self.llbb().end_with_void_return(self.loc) } fn ret(&mut self, mut value: RValue<'gcc>) { if self.structs_as_pointer.borrow().contains(&value) { // NOTE: hack to workaround a limitation of the rustc API: see comment on // CodegenCx.structs_as_pointer - value = value.dereference(None).to_rvalue(); + value = value.dereference(self.loc).to_rvalue(); } let expected_return_type = self.current_func().get_return_type(); if !expected_return_type.is_compatible_with(value.get_type()) { // NOTE: due to opaque pointers now being used, we need to cast here. - value = self.context.new_cast(None, value, expected_return_type); + value = self.context.new_cast(self.loc, value, expected_return_type); } - self.llbb().end_with_return(None, value); + self.llbb().end_with_return(self.loc, value); } fn br(&mut self, dest: Block<'gcc>) { - self.llbb().end_with_jump(None, dest) + self.llbb().end_with_jump(self.loc, dest) } fn cond_br(&mut self, cond: RValue<'gcc>, then_block: Block<'gcc>, else_block: Block<'gcc>) { - self.llbb().end_with_conditional(None, cond, then_block, else_block) + self.llbb().end_with_conditional(self.loc, cond, then_block, else_block) } fn switch(&mut self, value: RValue<'gcc>, default_block: Block<'gcc>, cases: impl ExactSizeIterator<Item = (u128, Block<'gcc>)>) { @@ -461,7 +463,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { let on_val = self.const_uint_big(typ, on_val); gcc_cases.push(self.context.new_case(on_val, on_val, dest)); } - self.block.end_with_switch(None, value, default_block, &gcc_cases); + self.block.end_with_switch(self.loc, value, default_block, &gcc_cases); } #[cfg(feature="master")] @@ -474,20 +476,20 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { self.block = current_block; let return_value = self.current_func() - .new_local(None, call.get_type(), "invokeResult"); + .new_local(self.loc, call.get_type(), "invokeResult"); - try_block.add_assignment(None, return_value, call); + try_block.add_assignment(self.loc, return_value, call); - try_block.end_with_jump(None, then); + try_block.end_with_jump(self.loc, then); if self.cleanup_blocks.borrow().contains(&catch) { - self.block.add_try_finally(None, try_block, catch); + self.block.add_try_finally(self.loc, try_block, catch); } else { - self.block.add_try_catch(None, try_block, catch); + self.block.add_try_catch(self.loc, try_block, catch); } - self.block.end_with_jump(None, then); + self.block.end_with_jump(self.loc, then); return_value.to_rvalue() } @@ -496,7 +498,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { fn invoke(&mut self, typ: Type<'gcc>, fn_attrs: Option<&CodegenFnAttrs>, fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>, func: RValue<'gcc>, args: &[RValue<'gcc>], then: Block<'gcc>, catch: Block<'gcc>, _funclet: Option<&Funclet>) -> RValue<'gcc> { let call_site = self.call(typ, fn_attrs, None, func, args, None); let condition = self.context.new_rvalue_from_int(self.bool_type, 1); - self.llbb().end_with_conditional(None, condition, then, catch); + self.llbb().end_with_conditional(self.loc, condition, then, catch); if let Some(_fn_abi) = fn_abi { // TODO(bjorn3): Apply function attributes } @@ -505,16 +507,16 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { fn unreachable(&mut self) { let func = self.context.get_builtin_function("__builtin_unreachable"); - self.block.add_eval(None, self.context.new_call(None, func, &[])); + self.block.add_eval(self.loc, self.context.new_call(self.loc, func, &[])); let return_type = self.block.get_function().get_return_type(); let void_type = self.context.new_type::<()>(); if return_type == void_type { - self.block.end_with_void_return(None) + self.block.end_with_void_return(self.loc) } else { let return_value = self.current_func() - .new_local(None, return_type, "unreachableReturn"); - self.block.end_with_return(None, return_value) + .new_local(self.loc, return_type, "unreachableReturn"); + self.block.end_with_return(self.loc, return_value) } } @@ -539,7 +541,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { } fn fmul(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { - a * b + self.cx.context.new_binary_op(self.loc, BinaryOp::Mult, a.get_type(), a, b) } fn udiv(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { @@ -564,7 +566,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { // 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 b = self.context.new_cast(None, b, typ); + let b = self.context.new_cast(self.loc, b, typ); a / b } @@ -611,9 +613,9 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { if a_type.is_compatible_with(self.cx.float_type) { let fmodf = self.context.get_builtin_function("fmodf"); // FIXME(antoyo): this seems to produce the wrong result. - return self.context.new_call(None, fmodf, &[a, b]); + return self.context.new_call(self.loc, fmodf, &[a, b]); } - else if let Some(vector_type) = a_type_unqualified.dyncast_vector() { + if let Some(vector_type) = a_type_unqualified.dyncast_vector() { assert_eq!(a_type_unqualified, b.get_type().unqualified()); let num_units = vector_type.get_num_units(); @@ -626,12 +628,12 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { }) .collect(); - return self.context.new_rvalue_from_vector(None, a_type, &new_elements) + return self.context.new_rvalue_from_vector(self.loc, a_type, &new_elements) } assert_eq!(a_type_unqualified, self.cx.double_type); let fmod = self.context.get_builtin_function("fmod"); - return self.context.new_call(None, fmod, &[a, b]); + self.context.new_call(self.loc, fmod, &[a, b]) } fn shl(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { @@ -653,73 +655,75 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { } fn or(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { - self.cx.gcc_or(a, b) + self.cx.gcc_or(a, b, self.loc) } fn xor(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { - self.gcc_xor(a, b) + set_rval_location(self, self.gcc_xor(a, b)) } fn neg(&mut self, a: RValue<'gcc>) -> RValue<'gcc> { - self.gcc_neg(a) + set_rval_location(self, self.gcc_neg(a)) } fn fneg(&mut self, a: RValue<'gcc>) -> RValue<'gcc> { - self.cx.context.new_unary_op(None, UnaryOp::Minus, a.get_type(), a) + set_rval_location(self, self.cx.context.new_unary_op(self.loc, UnaryOp::Minus, a.get_type(), a)) } fn not(&mut self, a: RValue<'gcc>) -> RValue<'gcc> { - self.gcc_not(a) + set_rval_location(self, self.gcc_not(a)) } fn unchecked_sadd(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { - self.gcc_add(a, b) + set_rval_location(self, self.gcc_add(a, b)) } fn unchecked_uadd(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { - self.gcc_add(a, b) + set_rval_location(self, self.gcc_add(a, b)) } fn unchecked_ssub(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { - self.gcc_sub(a, b) + set_rval_location(self, self.gcc_sub(a, b)) } fn unchecked_usub(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { // TODO(antoyo): should generate poison value? - self.gcc_sub(a, b) + set_rval_location(self, self.gcc_sub(a, b)) } fn unchecked_smul(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { - self.gcc_mul(a, b) + set_rval_location(self, self.gcc_mul(a, b)) } fn unchecked_umul(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { - self.gcc_mul(a, b) + set_rval_location(self, self.gcc_mul(a, b)) } fn fadd_fast(&mut self, lhs: RValue<'gcc>, rhs: RValue<'gcc>) -> RValue<'gcc> { // NOTE: it seems like we cannot enable fast-mode for a single operation in GCC. - lhs + rhs + set_rval_location(self, lhs + rhs) } fn fsub_fast(&mut self, lhs: RValue<'gcc>, rhs: RValue<'gcc>) -> RValue<'gcc> { // NOTE: it seems like we cannot enable fast-mode for a single operation in GCC. - lhs - rhs + set_rval_location(self, lhs - rhs) } fn fmul_fast(&mut self, lhs: RValue<'gcc>, rhs: RValue<'gcc>) -> RValue<'gcc> { // NOTE: it seems like we cannot enable fast-mode for a single operation in GCC. - lhs * rhs + set_rval_location(self, lhs * rhs) } fn fdiv_fast(&mut self, lhs: RValue<'gcc>, rhs: RValue<'gcc>) -> RValue<'gcc> { // NOTE: it seems like we cannot enable fast-mode for a single operation in GCC. - lhs / rhs + set_rval_location(self, lhs / rhs) } fn frem_fast(&mut self, lhs: RValue<'gcc>, rhs: RValue<'gcc>) -> RValue<'gcc> { // NOTE: it seems like we cannot enable fast-mode for a single operation in GCC. - self.frem(lhs, rhs) + let result = self.frem(lhs, rhs); + set_rval_location(self, result); + result } fn checked_binop(&mut self, oop: OverflowOp, typ: Ty<'_>, lhs: Self::Value, rhs: Self::Value) -> (Self::Value, Self::Value) { @@ -738,7 +742,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { }; // 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) + self.current_func().new_local(self.loc, aligned_type, &format!("stack_var_{}", self.stack_var_count.get())).get_address(self.loc) } fn byte_array_alloca(&mut self, _len: RValue<'gcc>, _align: Align) -> RValue<'gcc> { @@ -760,17 +764,17 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { else { pointee_ty.get_aligned(align.bytes()) }; - let ptr = self.context.new_cast(None, ptr, aligned_type.make_pointer()); - let deref = ptr.dereference(None).to_rvalue(); + let ptr = self.context.new_cast(self.loc, ptr, aligned_type.make_pointer()); + let deref = ptr.dereference(self.loc).to_rvalue(); unsafe { RETURN_VALUE_COUNT += 1 }; - let loaded_value = function.new_local(None, aligned_type, &format!("loadedValue{}", unsafe { RETURN_VALUE_COUNT })); - block.add_assignment(None, loaded_value, deref); + let loaded_value = function.new_local(self.loc, aligned_type, &format!("loadedValue{}", unsafe { RETURN_VALUE_COUNT })); + block.add_assignment(self.loc, loaded_value, deref); loaded_value.to_rvalue() } fn volatile_load(&mut self, ty: Type<'gcc>, ptr: RValue<'gcc>) -> RValue<'gcc> { - let ptr = self.context.new_cast(None, ptr, ty.make_volatile().make_pointer()); - ptr.dereference(None).to_rvalue() + let ptr = self.context.new_cast(self.loc, ptr, ty.make_volatile().make_pointer()); + ptr.dereference(self.loc).to_rvalue() } fn atomic_load(&mut self, _ty: Type<'gcc>, ptr: RValue<'gcc>, order: AtomicOrdering, size: Size) -> RValue<'gcc> { @@ -783,8 +787,8 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { .make_const() .make_volatile() .make_pointer(); - let ptr = self.context.new_cast(None, ptr, volatile_const_void_ptr_type); - self.context.new_call(None, atomic_load, &[ptr, ordering]) + let ptr = self.context.new_cast(self.loc, ptr, volatile_const_void_ptr_type); + self.context.new_call(self.loc, atomic_load, &[ptr, ordering]) } fn load_operand(&mut self, place: PlaceRef<'tcx, RValue<'gcc>>) -> OperandRef<'tcx, RValue<'gcc>> { @@ -859,7 +863,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { let next_bb = self.append_sibling_block("repeat_loop_next"); let ptr_type = start.get_type(); - let current = self.llbb().get_function().new_local(None, ptr_type, "loop_var"); + let current = self.llbb().get_function().new_local(self.loc, ptr_type, "loop_var"); let current_val = current.to_rvalue(); self.assign(current, start); @@ -874,7 +878,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { cg_elem.val.store(self, PlaceRef::new_sized_aligned(current_val, cg_elem.layout, align)); let next = self.inbounds_gep(self.backend_type(cg_elem.layout), current.to_rvalue(), &[self.const_usize(1)]); - self.llbb().add_assignment(None, current, next); + self.llbb().add_assignment(self.loc, current, next); self.br(header_bb); self.switch_to_block(next_bb); @@ -894,14 +898,14 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { fn store_with_flags(&mut self, val: RValue<'gcc>, ptr: RValue<'gcc>, align: Align, _flags: MemFlags) -> RValue<'gcc> { let ptr = self.check_store(val, ptr); - let destination = ptr.dereference(None); + let destination = ptr.dereference(self.loc); // NOTE: libgccjit does not support specifying the alignment on the assignment, so we cast // to type so it gets the proper alignment. let destination_type = destination.to_rvalue().get_type().unqualified(); let aligned_type = destination_type.get_aligned(align.bytes()).make_pointer(); - let aligned_destination = self.cx.context.new_bitcast(None, ptr, aligned_type); - let aligned_destination = aligned_destination.dereference(None); - self.llbb().add_assignment(None, aligned_destination, val); + let aligned_destination = self.cx.context.new_bitcast(self.loc, ptr, aligned_type); + let aligned_destination = aligned_destination.dereference(self.loc); + self.llbb().add_assignment(self.loc, aligned_destination, val); // 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()) @@ -914,26 +918,26 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { let volatile_const_void_ptr_type = self.context.new_type::<()>() .make_volatile() .make_pointer(); - let ptr = self.context.new_cast(None, ptr, volatile_const_void_ptr_type); + let ptr = self.context.new_cast(self.loc, ptr, volatile_const_void_ptr_type); // 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(); - let value = self.context.new_cast(None, value, int_type); + let value = self.context.new_cast(self.loc, value, int_type); self.llbb() - .add_eval(None, self.context.new_call(None, atomic_store, &[ptr, value, ordering])); + .add_eval(self.loc, self.context.new_call(self.loc, atomic_store, &[ptr, value, ordering])); } fn gep(&mut self, typ: Type<'gcc>, ptr: RValue<'gcc>, indices: &[RValue<'gcc>]) -> RValue<'gcc> { // NOTE: due to opaque pointers now being used, we need to cast here. - let ptr = self.context.new_cast(None, ptr, typ.make_pointer()); + let ptr = self.context.new_cast(self.loc, ptr, typ.make_pointer()); let ptr_type = ptr.get_type(); let mut pointee_type = ptr.get_type(); // NOTE: we cannot use array indexing here like in inbounds_gep because array indexing is // always considered in bounds in GCC (TODO(antoyo): to be verified). // So, we have to cast to a number. - let mut result = self.context.new_bitcast(None, ptr, self.sizet_type); + let mut result = self.context.new_bitcast(self.loc, ptr, self.sizet_type); // FIXME(antoyo): if there were more than 1 index, this code is probably wrong and would // require dereferencing the pointer. for index in indices { @@ -941,49 +945,49 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { #[cfg(feature="master")] let pointee_size = { let size = self.cx.context.new_sizeof(pointee_type); - self.context.new_cast(None, size, index.get_type()) + self.context.new_cast(self.loc, size, index.get_type()) }; #[cfg(not(feature="master"))] let pointee_size = self.context.new_rvalue_from_int(index.get_type(), pointee_type.get_size() as i32); result = result + self.gcc_int_cast(*index * pointee_size, self.sizet_type); } - self.context.new_bitcast(None, result, ptr_type) + self.context.new_bitcast(self.loc, result, ptr_type) } fn inbounds_gep(&mut self, typ: Type<'gcc>, ptr: RValue<'gcc>, indices: &[RValue<'gcc>]) -> RValue<'gcc> { // NOTE: due to opaque pointers now being used, we need to cast here. - let ptr = self.context.new_cast(None, ptr, typ.make_pointer()); + let ptr = self.context.new_cast(self.loc, ptr, typ.make_pointer()); // NOTE: array indexing is always considered in bounds in GCC (TODO(antoyo): to be verified). let mut indices = indices.into_iter(); let index = indices.next().expect("first index in inbounds_gep"); - let mut result = self.context.new_array_access(None, ptr, *index); + let mut result = self.context.new_array_access(self.loc, ptr, *index); for index in indices { - result = self.context.new_array_access(None, result, *index); + result = self.context.new_array_access(self.loc, result, *index); } - result.get_address(None) + result.get_address(self.loc) } fn struct_gep(&mut self, value_type: Type<'gcc>, ptr: RValue<'gcc>, idx: u64) -> RValue<'gcc> { // 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(); + let value = ptr.dereference(self.loc).to_rvalue(); if value_type.dyncast_array().is_some() { let index = self.context.new_rvalue_from_long(self.u64_type, i64::try_from(idx).expect("i64::try_from")); - let element = self.context.new_array_access(None, value, index); - element.get_address(None) + let element = self.context.new_array_access(self.loc, value, index); + element.get_address(self.loc) } else if let Some(vector_type) = value_type.dyncast_vector() { let array_type = vector_type.get_element_type().make_pointer(); let array = self.bitcast(ptr, array_type); let index = self.context.new_rvalue_from_long(self.u64_type, i64::try_from(idx).expect("i64::try_from")); - let element = self.context.new_array_access(None, array, index); - element.get_address(None) + let element = self.context.new_array_access(self.loc, array, index); + element.get_address(self.loc) } else if let Some(struct_type) = value_type.is_struct() { // NOTE: due to opaque pointers now being used, we need to bitcast here. let ptr = self.bitcast_if_needed(ptr, value_type.make_pointer()); - ptr.dereference_field(None, struct_type.get_field(idx as i32)).get_address(None) + ptr.dereference_field(self.loc, struct_type.get_field(idx as i32)).get_address(self.loc) } else { panic!("Unexpected type {:?}", value_type); @@ -1002,32 +1006,32 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { // TODO(antoyo): nothing to do as it is only for LLVM? return value; } - self.context.new_cast(None, value, dest_ty) + self.context.new_cast(self.loc, value, dest_ty) } fn fptoui(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> { - self.gcc_float_to_uint_cast(value, dest_ty) + set_rval_location(self, self.gcc_float_to_uint_cast(value, dest_ty)) } fn fptosi(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> { - self.gcc_float_to_int_cast(value, dest_ty) + set_rval_location(self, self.gcc_float_to_int_cast(value, dest_ty)) } fn uitofp(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> { - self.gcc_uint_to_float_cast(value, dest_ty) + set_rval_location(self, self.gcc_uint_to_float_cast(value, dest_ty)) } fn sitofp(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> { - self.gcc_int_to_float_cast(value, dest_ty) + set_rval_location(self, self.gcc_int_to_float_cast(value, dest_ty)) } fn fptrunc(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> { // TODO(antoyo): make sure it truncates. - self.context.new_cast(None, value, dest_ty) + set_rval_location(self, self.context.new_cast(self.loc, value, dest_ty)) } fn fpext(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> { - self.context.new_cast(None, value, dest_ty) + set_rval_location(self, self.context.new_cast(self.loc, value, dest_ty)) } fn ptrtoint(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> { @@ -1055,13 +1059,13 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { (false, true) => { // NOTE: Projecting a field of a pointer type will attempt a cast from a signed char to // a pointer, which is not supported by gccjit. - return self.cx.context.new_cast(None, self.inttoptr(value, val_type.make_pointer()), dest_ty); + self.cx.context.new_cast(self.loc, self.inttoptr(value, val_type.make_pointer()), dest_ty) }, (false, false) => { // When they are not pointers, we want a transmute (or reinterpret_cast). self.bitcast(value, dest_ty) }, - (true, true) => self.cx.context.new_cast(None, value, dest_ty), + (true, true) => self.cx.context.new_cast(self.loc, value, dest_ty), (true, false) => unimplemented!(), } } @@ -1072,7 +1076,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { } fn fcmp(&mut self, op: RealPredicate, lhs: RValue<'gcc>, rhs: RValue<'gcc>) -> RValue<'gcc> { - self.context.new_comparison(None, op.to_gcc_comparison(), lhs, rhs) + self.context.new_comparison(self.loc, op.to_gcc_comparison(), lhs, rhs) } /* Miscellaneous instructions */ @@ -1084,7 +1088,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { let src = self.pointercast(src, self.type_ptr_to(self.type_void())); let memcpy = self.context.get_builtin_function("memcpy"); // TODO(antoyo): handle aligns and is_volatile. - self.block.add_eval(None, self.context.new_call(None, memcpy, &[dst, src, size])); + self.block.add_eval(self.loc, self.context.new_call(self.loc, memcpy, &[dst, src, size])); } fn memmove(&mut self, dst: RValue<'gcc>, dst_align: Align, src: RValue<'gcc>, src_align: Align, size: RValue<'gcc>, flags: MemFlags) { @@ -1102,7 +1106,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { let memmove = self.context.get_builtin_function("memmove"); // TODO(antoyo): handle is_volatile. - self.block.add_eval(None, self.context.new_call(None, memmove, &[dst, src, size])); + self.block.add_eval(self.loc, self.context.new_call(self.loc, memmove, &[dst, src, size])); } fn memset(&mut self, ptr: RValue<'gcc>, fill_byte: RValue<'gcc>, size: RValue<'gcc>, _align: Align, flags: MemFlags) { @@ -1110,27 +1114,27 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { let ptr = self.pointercast(ptr, self.type_i8p()); let memset = self.context.get_builtin_function("memset"); // TODO(antoyo): handle align and is_volatile. - let fill_byte = self.context.new_cast(None, fill_byte, self.i32_type); + let fill_byte = self.context.new_cast(self.loc, fill_byte, self.i32_type); let size = self.intcast(size, self.type_size_t(), false); - self.block.add_eval(None, self.context.new_call(None, memset, &[ptr, fill_byte, size])); + self.block.add_eval(self.loc, self.context.new_call(self.loc, memset, &[ptr, fill_byte, size])); } fn select(&mut self, cond: RValue<'gcc>, then_val: RValue<'gcc>, mut else_val: RValue<'gcc>) -> RValue<'gcc> { let func = self.current_func(); - let variable = func.new_local(None, then_val.get_type(), "selectVar"); + let variable = func.new_local(self.loc, then_val.get_type(), "selectVar"); let then_block = func.new_block("then"); let else_block = func.new_block("else"); let after_block = func.new_block("after"); - self.llbb().end_with_conditional(None, cond, then_block, else_block); + self.llbb().end_with_conditional(self.loc, cond, then_block, else_block); - then_block.add_assignment(None, variable, then_val); - then_block.end_with_jump(None, after_block); + then_block.add_assignment(self.loc, variable, then_val); + then_block.end_with_jump(self.loc, after_block); if !then_val.get_type().is_compatible_with(else_val.get_type()) { - else_val = self.context.new_cast(None, else_val, then_val.get_type()); + else_val = self.context.new_cast(self.loc, else_val, then_val.get_type()); } - else_block.add_assignment(None, variable, else_val); - else_block.end_with_jump(None, after_block); + else_block.add_assignment(self.loc, variable, else_val); + else_block.end_with_jump(self.loc, after_block); // NOTE: since jumps were added in a place rustc does not expect, the current block in the // state need to be updated. @@ -1146,7 +1150,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { #[cfg(feature="master")] fn extract_element(&mut self, vec: RValue<'gcc>, idx: RValue<'gcc>) -> RValue<'gcc> { - self.context.new_vector_access(None, vec, idx).to_rvalue() + self.context.new_vector_access(self.loc, vec, idx).to_rvalue() } #[cfg(not(feature="master"))] @@ -1154,9 +1158,9 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { let vector_type = vec.get_type().unqualified().dyncast_vector().expect("Called extract_element on a non-vector type"); let element_type = vector_type.get_element_type(); let vec_num_units = vector_type.get_num_units(); - let array_type = self.context.new_array_type(None, element_type, vec_num_units as u64); - let array = self.context.new_bitcast(None, vec, array_type).to_rvalue(); - self.context.new_array_access(None, array, idx).to_rvalue() + let array_type = self.context.new_array_type(self.loc, element_type, vec_num_units as u64); + let array = self.context.new_bitcast(self.loc, vec, array_type).to_rvalue(); + self.context.new_array_access(self.loc, array, idx).to_rvalue() } fn vector_splat(&mut self, _num_elts: usize, _elt: RValue<'gcc>) -> RValue<'gcc> { @@ -1170,8 +1174,8 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { if value_type.dyncast_array().is_some() { let index = self.context.new_rvalue_from_long(self.u64_type, i64::try_from(idx).expect("i64::try_from")); - let element = self.context.new_array_access(None, aggregate_value, index); - element.get_address(None) + let element = self.context.new_array_access(self.loc, aggregate_value, index); + element.get_address(self.loc) } else if value_type.dyncast_vector().is_some() { panic!(); @@ -1180,14 +1184,14 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { if let Some(struct_type) = pointer_type.is_struct() { // NOTE: hack to workaround a limitation of the rustc API: see comment on // CodegenCx.structs_as_pointer - aggregate_value.dereference_field(None, struct_type.get_field(idx as i32)).to_rvalue() + aggregate_value.dereference_field(self.loc, struct_type.get_field(idx as i32)).to_rvalue() } else { panic!("Unexpected type {:?}", value_type); } } else if let Some(struct_type) = value_type.is_struct() { - aggregate_value.access_field(None, struct_type.get_field(idx as i32)).to_rvalue() + aggregate_value.access_field(self.loc, struct_type.get_field(idx as i32)).to_rvalue() } else { panic!("Unexpected type {:?}", value_type); @@ -1202,7 +1206,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { let lvalue = if value_type.dyncast_array().is_some() { let index = self.context.new_rvalue_from_long(self.u64_type, i64::try_from(idx).expect("i64::try_from")); - self.context.new_array_access(None, aggregate_value, index) + self.context.new_array_access(self.loc, aggregate_value, index) } else if value_type.dyncast_vector().is_some() { panic!(); @@ -1211,7 +1215,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { if let Some(struct_type) = pointer_type.is_struct() { // NOTE: hack to workaround a limitation of the rustc API: see comment on // CodegenCx.structs_as_pointer - aggregate_value.dereference_field(None, struct_type.get_field(idx as i32)) + aggregate_value.dereference_field(self.loc, struct_type.get_field(idx as i32)) } else { panic!("Unexpected type {:?}", value_type); @@ -1225,13 +1229,13 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { let value = // NOTE: sometimes, rustc will create a value with the wrong type. if lvalue_type != value.get_type() { - self.context.new_cast(None, value, lvalue_type) + self.context.new_cast(self.loc, value, lvalue_type) } else { value }; - self.llbb().add_assignment(None, lvalue, value); + self.llbb().add_assignment(self.loc, lvalue, value); aggregate_value } @@ -1254,10 +1258,10 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { let eh_pointer_builtin = self.cx.context.get_target_builtin_function("__builtin_eh_pointer"); let zero = self.cx.context.new_rvalue_zero(self.int_type); - let ptr = self.cx.context.new_call(None, eh_pointer_builtin, &[zero]); + let ptr = self.cx.context.new_call(self.loc, eh_pointer_builtin, &[zero]); let value1_type = self.u8_type.make_pointer(); - let ptr = self.cx.context.new_cast(None, ptr, value1_type); + let ptr = self.cx.context.new_cast(self.loc, ptr, value1_type); let value1 = ptr; let value2 = zero; // TODO(antoyo): set the proper value here (the type of exception?). @@ -1266,9 +1270,9 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { #[cfg(not(feature="master"))] fn cleanup_landing_pad(&mut self, _pers_fn: RValue<'gcc>) -> (RValue<'gcc>, RValue<'gcc>) { - let value1 = self.current_func().new_local(None, self.u8_type.make_pointer(), "landing_pad0") + let value1 = self.current_func().new_local(self.loc, self.u8_type.make_pointer(), "landing_pad0") .to_rvalue(); - let value2 = self.current_func().new_local(None, self.i32_type, "landing_pad1").to_rvalue(); + let value2 = self.current_func().new_local(self.loc, self.i32_type, "landing_pad1").to_rvalue(); (value1, value2) } @@ -1280,9 +1284,9 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { #[cfg(feature="master")] fn resume(&mut self, exn0: RValue<'gcc>, _exn1: RValue<'gcc>) { let exn_type = exn0.get_type(); - let exn = self.context.new_cast(None, exn0, exn_type); + let exn = self.context.new_cast(self.loc, exn0, exn_type); let unwind_resume = self.context.get_target_builtin_function("__builtin_unwind_resume"); - self.llbb().add_eval(None, self.context.new_call(None, unwind_resume, &[exn])); + self.llbb().add_eval(self.loc, self.context.new_call(self.loc, unwind_resume, &[exn])); self.unreachable(); } @@ -1329,8 +1333,8 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { // NOTE: since success contains the call to the intrinsic, it must be added to the basic block before // expected so that we store expected after the call. - let success_var = self.current_func().new_local(None, self.bool_type, "success"); - self.llbb().add_assignment(None, success_var, success); + let success_var = self.current_func().new_local(self.loc, self.bool_type, "success"); + self.llbb().add_assignment(self.loc, success_var, success); (expected.to_rvalue(), success_var.to_rvalue()) } @@ -1358,12 +1362,12 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { 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); + let dst = self.context.new_cast(self.loc, dst, volatile_void_ptr_type); // 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]); - self.context.new_cast(None, res, src.get_type()) + let src = self.context.new_cast(self.loc, src, new_src_type); + let res = self.context.new_call(self.loc, atomic_function, &[dst, src, order]); + self.context.new_cast(self.loc, res, src.get_type()) } fn atomic_fence(&mut self, order: AtomicOrdering, scope: SynchronizationScope) { @@ -1374,7 +1378,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { }; let thread_fence = self.context.get_builtin_function(name); let order = self.context.new_rvalue_from_int(self.i32_type, order.to_gcc()); - self.llbb().add_eval(None, self.context.new_call(None, thread_fence, &[order])); + self.llbb().add_eval(self.loc, self.context.new_call(self.loc, thread_fence, &[order])); } fn set_invariant_load(&mut self, load: RValue<'gcc>) { @@ -1650,7 +1654,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { }; for i in 0..mask_num_units { let field = struct_type.get_field(i as i32); - vector_elements.push(self.context.new_cast(None, mask.access_field(None, field).to_rvalue(), mask_element_type)); + vector_elements.push(self.context.new_cast(self.loc, mask.access_field(self.loc, field).to_rvalue(), mask_element_type)); } // NOTE: the mask needs to be the same length as the input vectors, so add the missing @@ -1666,14 +1670,14 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { // vectors and create a dummy second vector. let mut elements = vec![]; for i in 0..vec_num_units { - elements.push(self.context.new_vector_access(None, v1, self.context.new_rvalue_from_int(self.int_type, i as i32)).to_rvalue()); + elements.push(self.context.new_vector_access(self.loc, v1, self.context.new_rvalue_from_int(self.int_type, i as i32)).to_rvalue()); } for i in 0..(mask_num_units - vec_num_units) { - elements.push(self.context.new_vector_access(None, v2, self.context.new_rvalue_from_int(self.int_type, i as i32)).to_rvalue()); + elements.push(self.context.new_vector_access(self.loc, v2, self.context.new_rvalue_from_int(self.int_type, i as i32)).to_rvalue()); } - let v1 = self.context.new_rvalue_from_vector(None, result_type, &elements); + let v1 = self.context.new_rvalue_from_vector(self.loc, result_type, &elements); let zero = self.context.new_rvalue_zero(element_type); - let v2 = self.context.new_rvalue_from_vector(None, result_type, &vec![zero; mask_num_units]); + let v2 = self.context.new_rvalue_from_vector(self.loc, result_type, &vec![zero; mask_num_units]); (v1, v2) } else { @@ -1682,17 +1686,17 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let new_mask_num_units = std::cmp::max(mask_num_units, vec_num_units); let mask_type = self.context.new_vector_type(mask_element_type, new_mask_num_units as u64); - let mask = self.context.new_rvalue_from_vector(None, mask_type, &vector_elements); - let result = self.context.new_rvalue_vector_perm(None, v1, v2, mask); + let mask = self.context.new_rvalue_from_vector(self.loc, mask_type, &vector_elements); + let result = self.context.new_rvalue_vector_perm(self.loc, v1, v2, mask); if vec_num_units != mask_num_units { // NOTE: if padding was added, only select the number of elements of the masks to // remove that padding in the result. let mut elements = vec![]; for i in 0..mask_num_units { - elements.push(self.context.new_vector_access(None, result, self.context.new_rvalue_from_int(self.int_type, i as i32)).to_rvalue()); + elements.push(self.context.new_vector_access(self.loc, result, self.context.new_rvalue_from_int(self.int_type, i as i32)).to_rvalue()); } - self.context.new_rvalue_from_vector(None, result_type, &elements) + self.context.new_rvalue_from_vector(self.loc, result_type, &elements) } else { result @@ -1724,12 +1728,12 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { vector_elements.iter() .map(|i| self.context.new_rvalue_from_int(mask_element_type, ((i + shift) % element_count) as i32)) .collect(); - let mask = self.context.new_rvalue_from_vector(None, mask_type, &vector_elements); - let shifted = self.context.new_rvalue_vector_perm(None, res, res, mask); + let mask = self.context.new_rvalue_from_vector(self.loc, mask_type, &vector_elements); + let shifted = self.context.new_rvalue_vector_perm(self.loc, res, res, mask); shift *= 2; res = op(res, shifted, &self.context); } - self.context.new_vector_access(None, res, self.context.new_rvalue_zero(self.int_type)) + self.context.new_vector_access(self.loc, res, self.context.new_rvalue_zero(self.int_type)) .to_rvalue() } @@ -1741,7 +1745,8 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { } pub fn vector_reduce_op(&mut self, src: RValue<'gcc>, op: BinaryOp) -> RValue<'gcc> { - self.vector_reduce(src, |a, b, context| context.new_binary_op(None, op, a.get_type(), a, b)) + let loc = self.loc.clone(); + self.vector_reduce(src, |a, b, context| context.new_binary_op(loc, op, a.get_type(), a, b)) } pub fn vector_reduce_fadd_fast(&mut self, _acc: RValue<'gcc>, _src: RValue<'gcc>) -> RValue<'gcc> { @@ -1754,7 +1759,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let element_count = vector_type.get_num_units(); (0..element_count).into_iter() .map(|i| self.context - .new_vector_access(None, src, self.context.new_rvalue_from_int(self.int_type, i as _)) + .new_vector_access(self.loc, src, self.context.new_rvalue_from_int(self.int_type, i as _)) .to_rvalue()) .fold(acc, |x, i| x + i) } @@ -1774,7 +1779,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let element_count = vector_type.get_num_units(); (0..element_count).into_iter() .map(|i| self.context - .new_vector_access(None, src, self.context.new_rvalue_from_int(self.int_type, i as _)) + .new_vector_access(self.loc, src, self.context.new_rvalue_from_int(self.int_type, i as _)) .to_rvalue()) .fold(acc, |x, i| x * i) } @@ -1786,17 +1791,19 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { // Inspired by Hacker's Delight min implementation. pub fn vector_reduce_min(&mut self, src: RValue<'gcc>) -> RValue<'gcc> { + let loc = self.loc.clone(); self.vector_reduce(src, |a, b, context| { - let differences_or_zeros = difference_or_zero(a, b, context); - context.new_binary_op(None, BinaryOp::Plus, b.get_type(), b, differences_or_zeros) + let differences_or_zeros = difference_or_zero(loc, a, b, context); + context.new_binary_op(loc, BinaryOp::Plus, b.get_type(), b, differences_or_zeros) }) } // Inspired by Hacker's Delight max implementation. pub fn vector_reduce_max(&mut self, src: RValue<'gcc>) -> RValue<'gcc> { + let loc = self.loc.clone(); self.vector_reduce(src, |a, b, context| { - let differences_or_zeros = difference_or_zero(a, b, context); - context.new_binary_op(None, BinaryOp::Minus, a.get_type(), a, differences_or_zeros) + let differences_or_zeros = difference_or_zero(loc, a, b, context); + context.new_binary_op(loc, BinaryOp::Minus, a.get_type(), a, differences_or_zeros) }) } @@ -1805,23 +1812,23 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { // mask out the NaNs in b and replace them with the corresponding lane in a, so when a and // b get compared & spliced together, we get the numeric values instead of NaNs. - let b_nan_mask = self.context.new_comparison(None, ComparisonOp::NotEquals, b, b); + let b_nan_mask = self.context.new_comparison(self.loc, ComparisonOp::NotEquals, b, b); let mask_type = b_nan_mask.get_type(); - let b_nan_mask_inverted = self.context.new_unary_op(None, UnaryOp::BitwiseNegate, mask_type, b_nan_mask); - let a_cast = self.context.new_bitcast(None, a, mask_type); - let b_cast = self.context.new_bitcast(None, b, mask_type); + let b_nan_mask_inverted = self.context.new_unary_op(self.loc, UnaryOp::BitwiseNegate, mask_type, b_nan_mask); + let a_cast = self.context.new_bitcast(self.loc, a, mask_type); + let b_cast = self.context.new_bitcast(self.loc, b, mask_type); let res = (b_nan_mask & a_cast) | (b_nan_mask_inverted & b_cast); - let b = self.context.new_bitcast(None, res, vector_type); + let b = self.context.new_bitcast(self.loc, res, vector_type); // now do the actual comparison let comparison_op = match direction { ExtremumOperation::Min => ComparisonOp::LessThan, ExtremumOperation::Max => ComparisonOp::GreaterThan, }; - let cmp = self.context.new_comparison(None, comparison_op, a, b); - let cmp_inverted = self.context.new_unary_op(None, UnaryOp::BitwiseNegate, cmp.get_type(), cmp); + let cmp = self.context.new_comparison(self.loc, comparison_op, a, b); + let cmp_inverted = self.context.new_unary_op(self.loc, UnaryOp::BitwiseNegate, cmp.get_type(), cmp); let res = (cmp & a_cast) | (cmp_inverted & res); - self.context.new_bitcast(None, res, vector_type) + self.context.new_bitcast(self.loc, res, vector_type) } pub fn vector_fmin(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { @@ -1832,12 +1839,12 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { pub fn vector_reduce_fmin(&mut self, src: RValue<'gcc>) -> RValue<'gcc> { let vector_type = src.get_type().unqualified().dyncast_vector().expect("vector type"); let element_count = vector_type.get_num_units(); - let mut acc = self.context.new_vector_access(None, src, self.context.new_rvalue_zero(self.int_type)).to_rvalue(); + let mut acc = self.context.new_vector_access(self.loc, src, self.context.new_rvalue_zero(self.int_type)).to_rvalue(); for i in 1..element_count { let elem = self.context - .new_vector_access(None, src, self.context.new_rvalue_from_int(self.int_type, i as _)) + .new_vector_access(self.loc, src, self.context.new_rvalue_from_int(self.int_type, i as _)) .to_rvalue(); - let cmp = self.context.new_comparison(None, ComparisonOp::LessThan, acc, elem); + let cmp = self.context.new_comparison(self.loc, ComparisonOp::LessThan, acc, elem); acc = self.select(cmp, acc, elem); } acc @@ -1856,12 +1863,12 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { pub fn vector_reduce_fmax(&mut self, src: RValue<'gcc>) -> RValue<'gcc> { let vector_type = src.get_type().unqualified().dyncast_vector().expect("vector type"); let element_count = vector_type.get_num_units(); - let mut acc = self.context.new_vector_access(None, src, self.context.new_rvalue_zero(self.int_type)).to_rvalue(); + let mut acc = self.context.new_vector_access(self.loc, src, self.context.new_rvalue_zero(self.int_type)).to_rvalue(); for i in 1..element_count { let elem = self.context - .new_vector_access(None, src, self.context.new_rvalue_from_int(self.int_type, i as _)) + .new_vector_access(self.loc, src, self.context.new_rvalue_from_int(self.int_type, i as _)) .to_rvalue(); - let cmp = self.context.new_comparison(None, ComparisonOp::GreaterThan, acc, elem); + let cmp = self.context.new_comparison(self.loc, ComparisonOp::GreaterThan, acc, elem); acc = self.select(cmp, acc, elem); } acc @@ -1890,7 +1897,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { if then_val_element_size != element_type.get_size() { let new_element_type = self.type_ix(then_val_element_size as u64 * 8); let new_vector_type = self.context.new_vector_type(new_element_type, num_units as u64); - let cond = self.context.convert_vector(None, cond, new_vector_type); + let cond = self.context.convert_vector(self.loc, cond, new_vector_type); (cond, new_element_type) } else { @@ -1901,24 +1908,24 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let cond_type = cond.get_type(); let zeros = vec![self.context.new_rvalue_zero(element_type); num_units]; - let zeros = self.context.new_rvalue_from_vector(None, cond_type, &zeros); + let zeros = self.context.new_rvalue_from_vector(self.loc, cond_type, &zeros); let result_type = then_val.get_type(); - let masks = self.context.new_comparison(None, ComparisonOp::NotEquals, cond, zeros); + let masks = self.context.new_comparison(self.loc, ComparisonOp::NotEquals, cond, zeros); // NOTE: masks is a vector of integers, but the values can be vectors of floats, so use bitcast to make // the & operation work. let then_val = self.bitcast_if_needed(then_val, masks.get_type()); let then_vals = masks & then_val; let minus_ones = vec![self.context.new_rvalue_from_int(element_type, -1); num_units]; - let minus_ones = self.context.new_rvalue_from_vector(None, cond_type, &minus_ones); + let minus_ones = self.context.new_rvalue_from_vector(self.loc, cond_type, &minus_ones); let inverted_masks = masks ^ minus_ones; // NOTE: sometimes, the type of else_val can be different than the type of then_val in // libgccjit (vector of int vs vector of int32_t), but they should be the same for the AND // operation to work. // TODO: remove bitcast now that vector types can be compared? - let else_val = self.context.new_bitcast(None, else_val, then_val.get_type()); + let else_val = self.context.new_bitcast(self.loc, else_val, then_val.get_type()); let else_vals = inverted_masks & else_val; let res = then_vals | else_vals; @@ -1926,15 +1933,15 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { } } -fn difference_or_zero<'gcc>(a: RValue<'gcc>, b: RValue<'gcc>, context: &'gcc Context<'gcc>) -> RValue<'gcc> { +fn difference_or_zero<'gcc>(loc: Option<Location<'gcc>>, a: RValue<'gcc>, b: RValue<'gcc>, context: &'gcc Context<'gcc>) -> RValue<'gcc> { let difference = a - b; - let masks = context.new_comparison(None, ComparisonOp::GreaterThanEquals, b, a); + let masks = context.new_comparison(loc, ComparisonOp::GreaterThanEquals, b, a); // NOTE: masks is a vector of integers, but the values can be vectors of floats, so use bitcast to make // the & operation work. let a_type = a.get_type(); let masks = if masks.get_type() != a_type { - context.new_bitcast(None, masks, a_type) + context.new_bitcast(loc, masks, a_type) } else { masks @@ -1945,7 +1952,7 @@ fn difference_or_zero<'gcc>(a: RValue<'gcc>, b: RValue<'gcc>, context: &'gcc Con impl<'a, 'gcc, 'tcx> StaticBuilderMethods for Builder<'a, 'gcc, 'tcx> { fn get_static(&mut self, def_id: DefId) -> RValue<'gcc> { // Forward to the `get_static` method of `CodegenCx` - self.cx().get_static(def_id).get_address(None) + self.cx().get_static(def_id).get_address(self.loc) } } diff --git a/src/context.rs b/src/context.rs index 5760d96165d..cca37168880 100644 --- a/src/context.rs +++ b/src/context.rs @@ -1,6 +1,6 @@ use std::cell::{Cell, RefCell}; -use gccjit::{Block, CType, Context, Function, FunctionPtrType, FunctionType, LValue, RValue, Type}; +use gccjit::{Block, CType, Context, Function, FunctionPtrType, FunctionType, LValue, Location, RValue, Type}; use rustc_codegen_ssa::base::wants_msvc_seh; use rustc_codegen_ssa::traits::{ BackendTypes, @@ -345,7 +345,7 @@ impl<'gcc, 'tcx> BackendTypes for CodegenCx<'gcc, 'tcx> { type Funclet = (); // TODO(antoyo) type DIScope = (); // TODO(antoyo) - type DILocation = (); // TODO(antoyo) + type DILocation = Location<'gcc>; type DIVariable = (); // TODO(antoyo) } diff --git a/src/debuginfo.rs b/src/debuginfo.rs index d1bfd833cd8..cd01785edbf 100644 --- a/src/debuginfo.rs +++ b/src/debuginfo.rs @@ -1,41 +1,201 @@ -use gccjit::RValue; -use rustc_codegen_ssa::mir::debuginfo::{FunctionDebugContext, VariableKind}; +use gccjit::{Location, RValue}; +use rustc_codegen_ssa::mir::debuginfo::{DebugScope, FunctionDebugContext, VariableKind}; use rustc_codegen_ssa::traits::{DebugInfoBuilderMethods, DebugInfoMethods}; -use rustc_middle::mir; +use rustc_index::bit_set::BitSet; +use rustc_index::IndexVec; +use rustc_middle::mir::{Body, self, SourceScope}; use rustc_middle::ty::{Instance, PolyExistentialTraitRef, Ty}; -use rustc_span::{SourceFile, Span, Symbol}; +use rustc_session::config::DebugInfo; +use rustc_span::{BytePos, Pos, SourceFile, SourceFileAndLine, Span, Symbol}; use rustc_target::abi::call::FnAbi; use rustc_target::abi::Size; +use rustc_data_structures::sync::Lrc; +use crate::rustc_index::Idx; use std::ops::Range; use crate::builder::Builder; use crate::context::CodegenCx; +pub(super) const UNKNOWN_LINE_NUMBER: u32 = 0; +pub(super) const UNKNOWN_COLUMN_NUMBER: u32 = 0; + impl<'a, 'gcc, 'tcx> DebugInfoBuilderMethods for Builder<'a, 'gcc, 'tcx> { // FIXME(eddyb) find a common convention for all of the debuginfo-related // names (choose between `dbg`, `debug`, `debuginfo`, `debug_info` etc.). fn dbg_var_addr( &mut self, _dbg_var: Self::DIVariable, - _scope_metadata: Self::DIScope, - _variable_alloca: Self::Value, + dbg_loc: Self::DILocation, + variable_alloca: Self::Value, _direct_offset: Size, _indirect_offsets: &[Size], _fragment: Option<Range<Size>>, ) { - unimplemented!(); + // FIXME(tempdragon): Not sure if this is correct, probably wrong but still keep it here. + #[cfg(feature = "master")] + variable_alloca.set_location(dbg_loc); } fn insert_reference_to_gdb_debug_scripts_section_global(&mut self) { // TODO(antoyo): insert reference to gdb debug scripts section global. } + /// FIXME(tempdragon): Currently, this function is not yet implemented. It seems that the + /// debug name and the mangled name should both be included in the LValues. + /// Besides, a function to get the rvalue type(m_is_lvalue) should also be included. fn set_var_name(&mut self, _value: RValue<'gcc>, _name: &str) { - unimplemented!(); } - fn set_dbg_loc(&mut self, _dbg_loc: Self::DILocation) { - unimplemented!(); + fn set_dbg_loc(&mut self, dbg_loc: Self::DILocation) { + self.loc = Some(dbg_loc); + } +} + +/// Generate the `debug_context` in an MIR Body. +/// # Souce of Origin +/// Copied from `create_scope_map.rs` of rustc_codegen_llvm +fn compute_mir_scopes<'gcc, 'tcx>( + cx: &CodegenCx<'gcc, 'tcx>, + instance: Instance<'tcx>, + mir: &Body<'tcx>, + debug_context: &mut FunctionDebugContext<'tcx, (), Location<'gcc>>, +) { + // Find all scopes with variables defined in them. + let variables = if cx.sess().opts.debuginfo == DebugInfo::Full { + let mut vars = BitSet::new_empty(mir.source_scopes.len()); + // FIXME(eddyb) take into account that arguments always have debuginfo, + // irrespective of their name (assuming full debuginfo is enabled). + // NOTE(eddyb) actually, on second thought, those are always in the + // function scope, which always exists. + for var_debug_info in &mir.var_debug_info { + vars.insert(var_debug_info.source_info.scope); + } + Some(vars) + } else { + // Nothing to emit, of course. + None + }; + let mut instantiated = BitSet::new_empty(mir.source_scopes.len()); + // Instantiate all scopes. + for idx in 0..mir.source_scopes.len() { + let scope = SourceScope::new(idx); + make_mir_scope(cx, instance, mir, &variables, debug_context, &mut instantiated, scope); + } + assert!(instantiated.count() == mir.source_scopes.len()); +} + +/// Update the `debug_context`, adding new scope to it, +/// if it's not added as is denoted in `instantiated`. +/// +/// # Souce of Origin +/// Copied from `create_scope_map.rs` of rustc_codegen_llvm +/// FIXME(tempdragon/?): Add Scope Support Here. +fn make_mir_scope<'gcc, 'tcx>( + cx: &CodegenCx<'gcc, 'tcx>, + instance: Instance<'tcx>, + mir: &Body<'tcx>, + variables: &Option<BitSet<SourceScope>>, + debug_context: &mut FunctionDebugContext<'tcx, (), Location<'gcc>>, + instantiated: &mut BitSet<SourceScope>, + scope: SourceScope, +) { + if instantiated.contains(scope) { + return; + } + + let scope_data = &mir.source_scopes[scope]; + let parent_scope = if let Some(parent) = scope_data.parent_scope { + make_mir_scope(cx, instance, mir, variables, debug_context, instantiated, parent); + debug_context.scopes[parent] + } else { + // The root is the function itself. + let file = cx.sess().source_map().lookup_source_file(mir.span.lo()); + debug_context.scopes[scope] = DebugScope { + file_start_pos: file.start_pos, + file_end_pos: file.end_position(), + ..debug_context.scopes[scope] + }; + instantiated.insert(scope); + return; + }; + + if let Some(vars) = variables + { + if !vars.contains(scope) + && scope_data.inlined.is_none() { + // Do not create a DIScope if there are no variables defined in this + // MIR `SourceScope`, and it's not `inlined`, to avoid debuginfo bloat. + debug_context.scopes[scope] = parent_scope; + instantiated.insert(scope); + return; + } + } + + let loc = cx.lookup_debug_loc(scope_data.span.lo()); + + // FIXME(tempdragon): Add the scope related code here if the scope is supported. + let dbg_scope = (); + + let inlined_at = scope_data.inlined.map(|(_, callsite_span)| { + // FIXME(eddyb) this doesn't account for the macro-related + // `Span` fixups that `rustc_codegen_ssa::mir::debuginfo` does. + let callsite_scope = parent_scope.adjust_dbg_scope_for_span(cx, callsite_span); + cx.dbg_loc(callsite_scope, parent_scope.inlined_at, callsite_span) + }); + let p_inlined_at = parent_scope.inlined_at; + // TODO(tempdragon): dbg_scope: Add support for scope extension here. + inlined_at.or(p_inlined_at); + + debug_context.scopes[scope] = DebugScope { + dbg_scope, + inlined_at, + file_start_pos: loc.file.start_pos, + file_end_pos: loc.file.end_position(), + }; + instantiated.insert(scope); +} + +/// A source code location used to generate debug information. +// FIXME(eddyb) rename this to better indicate it's a duplicate of +// `rustc_span::Loc` rather than `DILocation`, perhaps by making +// `lookup_char_pos` return the right information instead. +pub struct DebugLoc { + /// Information about the original source file. + pub file: Lrc<SourceFile>, + /// The (1-based) line number. + pub line: u32, + /// The (1-based) column number. + pub col: u32, +} + +impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { + /// Looks up debug source information about a `BytePos`. + // FIXME(eddyb) rename this to better indicate it's a duplicate of + // `lookup_char_pos` rather than `dbg_loc`, perhaps by making + // `lookup_char_pos` return the right information instead. + // Source of Origin: cg_llvm + pub fn lookup_debug_loc(&self, pos: BytePos) -> DebugLoc { + let (file, line, col) = match self.sess().source_map().lookup_line(pos) { + Ok(SourceFileAndLine { sf: file, line }) => { + let line_pos = file.lines()[line]; + + // Use 1-based indexing. + let line = (line + 1) as u32; + let col = (file.relative_position(pos) - line_pos).to_u32() + 1; + + (file, line, col) + } + Err(file) => (file, UNKNOWN_LINE_NUMBER, UNKNOWN_COLUMN_NUMBER), + }; + + // For MSVC, omit the column number. + // Otherwise, emit it. This mimics clang behaviour. + // See discussion in https://github.com/rust-lang/rust/issues/42921 + if self.sess().target.is_like_msvc { + DebugLoc { file, line, col: UNKNOWN_COLUMN_NUMBER } + } else { + DebugLoc { file, line, col } + } } } @@ -51,13 +211,32 @@ impl<'gcc, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'gcc, 'tcx> { fn create_function_debug_context( &self, - _instance: Instance<'tcx>, - _fn_abi: &FnAbi<'tcx, Ty<'tcx>>, - _llfn: RValue<'gcc>, - _mir: &mir::Body<'tcx>, + instance: Instance<'tcx>, + fn_abi: &FnAbi<'tcx, Ty<'tcx>>, + llfn: RValue<'gcc>, + mir: &mir::Body<'tcx>, ) -> Option<FunctionDebugContext<'tcx, Self::DIScope, Self::DILocation>> { // TODO(antoyo) - None + if self.sess().opts.debuginfo == DebugInfo::None { + return None; + } + + // Initialize fn debug context (including scopes). + let empty_scope = DebugScope { + dbg_scope: self.dbg_scope_fn(instance, fn_abi, Some(llfn)), + inlined_at: None, + file_start_pos: BytePos(0), + file_end_pos: BytePos(0), + }; + let mut fn_debug_context = FunctionDebugContext { + scopes: IndexVec::from_elem(empty_scope, &mir.source_scopes.as_slice()), + inlined_function_scopes: Default::default(), + }; + + // Fill in all the scopes, with the information from the MIR body. + compute_mir_scopes(self, instance, mir, &mut fn_debug_context); + + Some(fn_debug_context) } fn extend_scope_to_file( @@ -65,11 +244,11 @@ impl<'gcc, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'gcc, 'tcx> { _scope_metadata: Self::DIScope, _file: &SourceFile, ) -> Self::DIScope { - unimplemented!(); + // TODO(antoyo): implement. } fn debuginfo_finalize(&self) { - // TODO(antoyo) + self.context.set_debug_info(true) } fn create_dbg_var( @@ -80,7 +259,7 @@ impl<'gcc, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'gcc, 'tcx> { _variable_kind: VariableKind, _span: Span, ) -> Self::DIVariable { - unimplemented!(); + () } fn dbg_scope_fn( @@ -89,15 +268,46 @@ impl<'gcc, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'gcc, 'tcx> { _fn_abi: &FnAbi<'tcx, Ty<'tcx>>, _maybe_definition_llfn: Option<RValue<'gcc>>, ) -> Self::DIScope { - unimplemented!(); + // TODO(antoyo): implement. } fn dbg_loc( &self, _scope: Self::DIScope, _inlined_at: Option<Self::DILocation>, - _span: Span, + span: Span, ) -> Self::DILocation { - unimplemented!(); + let pos = span.lo(); + let DebugLoc{file, line, col} = self.lookup_debug_loc(pos); + let loc = match &file.name { + rustc_span::FileName::Real(name) => match name { + rustc_span::RealFileName::LocalPath(name) => { + if let Some(name) = name.to_str() { + self.context + .new_location(name, line as i32, col as i32) + } else{ + Location::null() + } + } + rustc_span::RealFileName::Remapped { + local_path, + virtual_name:_, + } => if let Some(name) = local_path.as_ref() { + if let Some(name) = name.to_str(){ + self.context.new_location( + name, + line as i32, + col as i32, + ) + } else { + Location::null() + } + } else{ + Location::null() + }, + }, + _ => Location::null(), + }; + loc } } diff --git a/src/int.rs b/src/int.rs index b69e073c4d9..fe38d89ff8c 100644 --- a/src/int.rs +++ b/src/int.rs @@ -4,7 +4,7 @@ use std::convert::TryFrom; -use gccjit::{ComparisonOp, FunctionType, RValue, ToRValue, Type, UnaryOp, BinaryOp}; +use gccjit::{BinaryOp, ComparisonOp, FunctionType, Location, RValue, ToRValue, Type, UnaryOp}; use rustc_codegen_ssa::common::{IntPredicate, TypeKind}; use rustc_codegen_ssa::traits::{BackendTypes, BaseTypeMethods, BuilderMethods, OverflowOp}; use rustc_middle::ty::{ParamEnv, Ty}; @@ -35,13 +35,13 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { else { UnaryOp::BitwiseNegate }; - self.cx.context.new_unary_op(None, operation, typ, a) + self.cx.context.new_unary_op(self.loc, operation, typ, a) } else { let element_type = typ.dyncast_array().expect("element type"); self.from_low_high_rvalues(typ, - self.cx.context.new_unary_op(None, UnaryOp::BitwiseNegate, element_type, self.low(a)), - self.cx.context.new_unary_op(None, UnaryOp::BitwiseNegate, element_type, self.high(a)), + self.cx.context.new_unary_op(self.loc, UnaryOp::BitwiseNegate, element_type, self.low(a)), + self.cx.context.new_unary_op(self.loc, UnaryOp::BitwiseNegate, element_type, self.high(a)), ) } } @@ -49,7 +49,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { pub fn gcc_neg(&self, a: RValue<'gcc>) -> RValue<'gcc> { let a_type = a.get_type(); if self.is_native_int_type(a_type) || a_type.is_vector() { - self.cx.context.new_unary_op(None, UnaryOp::Minus, a.get_type(), a) + self.cx.context.new_unary_op(self.loc, UnaryOp::Minus, a.get_type(), a) } else { self.gcc_add(self.gcc_not(a), self.gcc_int(a_type, 1)) @@ -57,7 +57,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { } pub fn gcc_and(&self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { - self.cx.bitwise_operation(BinaryOp::BitwiseAnd, a, b) + self.cx.bitwise_operation(BinaryOp::BitwiseAnd, a, b, self.loc) } pub fn gcc_lshr(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { @@ -69,7 +69,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { // FIXME(antoyo): remove the casts when libgccjit can shift an unsigned number by a signed number. // TODO(antoyo): cast to unsigned to do a logical shift if that does not work. if a_type.is_signed(self) != b_type.is_signed(self) { - let b = self.context.new_cast(None, b, a_type); + let b = self.context.new_cast(self.loc, b, a_type); a >> b } else { @@ -95,14 +95,14 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let b0_block = func.new_block("b0"); let actual_else_block = func.new_block("actual_else"); - let result = func.new_local(None, a_type, "shiftResult"); + let result = func.new_local(self.loc, a_type, "shiftResult"); let sixty_four = self.gcc_int(native_int_type, 64); let sixty_three = self.gcc_int(native_int_type, 63); let zero = self.gcc_zero(native_int_type); let b = self.gcc_int_cast(b, native_int_type); let condition = self.gcc_icmp(IntPredicate::IntNE, self.gcc_and(b, sixty_four), zero); - self.llbb().end_with_conditional(None, condition, then_block, else_block); + self.llbb().end_with_conditional(self.loc, condition, then_block, else_block); let shift_value = self.gcc_sub(b, sixty_four); let high = self.high(a); @@ -114,27 +114,27 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { zero }; let array_value = self.from_low_high_rvalues(a_type, high >> shift_value, sign); - then_block.add_assignment(None, result, array_value); - then_block.end_with_jump(None, after_block); + then_block.add_assignment(self.loc, result, array_value); + then_block.end_with_jump(self.loc, after_block); let condition = self.gcc_icmp(IntPredicate::IntEQ, b, zero); - else_block.end_with_conditional(None, condition, b0_block, actual_else_block); + else_block.end_with_conditional(self.loc, condition, b0_block, actual_else_block); - b0_block.add_assignment(None, result, a); - b0_block.end_with_jump(None, after_block); + b0_block.add_assignment(self.loc, result, a); + b0_block.end_with_jump(self.loc, after_block); let shift_value = self.gcc_sub(sixty_four, b); // NOTE: cast low to its unsigned type in order to perform a logical right shift. let unsigned_type = native_int_type.to_unsigned(&self.cx); - let casted_low = self.context.new_cast(None, self.low(a), unsigned_type); - let shifted_low = casted_low >> self.context.new_cast(None, b, unsigned_type); - let shifted_low = self.context.new_cast(None, shifted_low, native_int_type); + let casted_low = self.context.new_cast(self.loc, self.low(a), unsigned_type); + let shifted_low = casted_low >> self.context.new_cast(self.loc, b, unsigned_type); + let shifted_low = self.context.new_cast(self.loc, shifted_low, native_int_type); let array_value = self.from_low_high_rvalues(a_type, (high << shift_value) | shifted_low, high >> b, ); - actual_else_block.add_assignment(None, result, array_value); - actual_else_block.end_with_jump(None, after_block); + actual_else_block.add_assignment(self.loc, result, array_value); + actual_else_block.end_with_jump(self.loc, after_block); // NOTE: since jumps were added in a place rustc does not expect, the current block in the // state need to be updated. @@ -152,13 +152,13 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { if a_type.is_vector() { // Vector types need to be bitcast. // TODO(antoyo): perhaps use __builtin_convertvector for vector casting. - b = self.context.new_bitcast(None, b, a.get_type()); + b = self.context.new_bitcast(self.loc, b, a.get_type()); } else { - b = self.context.new_cast(None, b, a.get_type()); + b = self.context.new_cast(self.loc, b, a.get_type()); } } - self.context.new_binary_op(None, operation, a_type, a, b) + self.context.new_binary_op(self.loc, operation, a_type, a, b) } else { debug_assert!(a_type.dyncast_array().is_some()); @@ -172,10 +172,10 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { (BinaryOp::Minus, false) => "__rust_u128_sub", _ => unreachable!("unexpected additive operation {:?}", operation), }; - let param_a = self.context.new_parameter(None, a_type, "a"); - let param_b = self.context.new_parameter(None, b_type, "b"); - let func = self.context.new_function(None, FunctionType::Extern, a_type, &[param_a, param_b], func_name, false); - self.context.new_call(None, func, &[a, b]) + let param_a = self.context.new_parameter(self.loc, a_type, "a"); + let param_b = self.context.new_parameter(self.loc, b_type, "b"); + let func = self.context.new_function(self.loc, FunctionType::Extern, a_type, &[param_a, param_b], func_name, false); + self.context.new_call(self.loc, func, &[a, b]) } } @@ -195,7 +195,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let a_type = a.get_type(); let b_type = b.get_type(); if (self.is_native_int_type_or_bool(a_type) && self.is_native_int_type_or_bool(b_type)) || (a_type.is_vector() && b_type.is_vector()) { - self.context.new_binary_op(None, operation, a_type, a, b) + self.context.new_binary_op(self.loc, operation, a_type, a, b) } else { debug_assert!(a_type.dyncast_array().is_some()); @@ -208,10 +208,10 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { "u" }; let func_name = format!("__{}{}ti3", sign, operation_name); - let param_a = self.context.new_parameter(None, a_type, "a"); - let param_b = self.context.new_parameter(None, b_type, "b"); - let func = self.context.new_function(None, FunctionType::Extern, a_type, &[param_a, param_b], func_name, false); - self.context.new_call(None, func, &[a, b]) + let param_a = self.context.new_parameter(self.loc, a_type, "a"); + let param_b = self.context.new_parameter(self.loc, b_type, "b"); + let func = self.context.new_function(self.loc, FunctionType::Extern, a_type, &[param_a, param_b], func_name, false); + self.context.new_call(self.loc, func, &[a, b]) } } @@ -335,10 +335,10 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let intrinsic = self.context.get_builtin_function(&name); let res = self.current_func() // TODO(antoyo): is it correct to use rhs type instead of the parameter typ? - .new_local(None, rhs.get_type(), "binopResult") - .get_address(None); + .new_local(self.loc, rhs.get_type(), "binopResult") + .get_address(self.loc); let overflow = self.overflow_call(intrinsic, &[lhs, rhs, res], None); - (res.dereference(None).to_rvalue(), overflow) + (res.dereference(self.loc).to_rvalue(), overflow) } pub fn operation_with_overflow(&self, func_name: &str, lhs: RValue<'gcc>, rhs: RValue<'gcc>) -> (RValue<'gcc>, RValue<'gcc>) { @@ -346,10 +346,10 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let b_type = rhs.get_type(); debug_assert!(a_type.dyncast_array().is_some()); debug_assert!(b_type.dyncast_array().is_some()); - let param_a = self.context.new_parameter(None, a_type, "a"); - let param_b = self.context.new_parameter(None, b_type, "b"); - let result_field = self.context.new_field(None, a_type, "result"); - let overflow_field = self.context.new_field(None, self.bool_type, "overflow"); + let param_a = self.context.new_parameter(self.loc, a_type, "a"); + let param_b = self.context.new_parameter(self.loc, b_type, "b"); + let result_field = self.context.new_field(self.loc, a_type, "result"); + let overflow_field = self.context.new_field(self.loc, self.bool_type, "overflow"); let ret_ty = Ty::new_tup(self.tcx, &[self.tcx.types.i128, self.tcx.types.bool]); let layout = self.tcx.layout_of(ParamEnv::reveal_all().and(ret_ty)).unwrap(); @@ -372,23 +372,23 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let indirect = matches!(fn_abi.ret.mode, PassMode::Indirect { .. }); - let return_type = self.context.new_struct_type(None, "result_overflow", &[result_field, overflow_field]); + let return_type = self.context.new_struct_type(self.loc, "result_overflow", &[result_field, overflow_field]); let result = if indirect { - let return_value = self.current_func().new_local(None, return_type.as_type(), "return_value"); + let return_value = self.current_func().new_local(self.loc, return_type.as_type(), "return_value"); let return_param_type = return_type.as_type().make_pointer(); - let return_param = self.context.new_parameter(None, return_param_type, "return_value"); - let func = self.context.new_function(None, FunctionType::Extern, self.type_void(), &[return_param, param_a, param_b], func_name, false); - self.llbb().add_eval(None, self.context.new_call(None, func, &[return_value.get_address(None), lhs, rhs])); + let return_param = self.context.new_parameter(self.loc, return_param_type, "return_value"); + let func = self.context.new_function(self.loc, FunctionType::Extern, self.type_void(), &[return_param, param_a, param_b], func_name, false); + self.llbb().add_eval(self.loc, self.context.new_call(self.loc, func, &[return_value.get_address(self.loc), lhs, rhs])); return_value.to_rvalue() } else { - let func = self.context.new_function(None, FunctionType::Extern, return_type.as_type(), &[param_a, param_b], func_name, false); - self.context.new_call(None, func, &[lhs, rhs]) + let func = self.context.new_function(self.loc, FunctionType::Extern, return_type.as_type(), &[param_a, param_b], func_name, false); + self.context.new_call(self.loc, func, &[lhs, rhs]) }; - let overflow = result.access_field(None, overflow_field); - let int_result = result.access_field(None, result_field); - return (int_result, overflow); + let overflow = result.access_field(self.loc, overflow_field); + let int_result = result.access_field(self.loc, result_field); + (int_result, overflow) } pub fn gcc_icmp(&mut self, op: IntPredicate, mut lhs: RValue<'gcc>, mut rhs: RValue<'gcc>) -> RValue<'gcc> { @@ -397,7 +397,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { if self.is_non_native_int_type(a_type) || self.is_non_native_int_type(b_type) { // This algorithm is based on compiler-rt's __cmpti2: // https://github.com/llvm-mirror/compiler-rt/blob/f0745e8476f069296a7c71accedd061dce4cdf79/lib/builtins/cmpti2.c#L21 - let result = self.current_func().new_local(None, self.int_type, "icmp_result"); + let result = self.current_func().new_local(self.loc, self.int_type, "icmp_result"); let block1 = self.current_func().new_block("block1"); let block2 = self.current_func().new_block("block2"); let block3 = self.current_func().new_block("block3"); @@ -413,35 +413,35 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { // the sign is only on high). let unsigned_type = native_int_type.to_unsigned(&self.cx); - let lhs_low = self.context.new_cast(None, self.low(lhs), unsigned_type); - let rhs_low = self.context.new_cast(None, self.low(rhs), unsigned_type); + let lhs_low = self.context.new_cast(self.loc, self.low(lhs), unsigned_type); + let rhs_low = self.context.new_cast(self.loc, self.low(rhs), unsigned_type); - let condition = self.context.new_comparison(None, ComparisonOp::LessThan, self.high(lhs), self.high(rhs)); - self.llbb().end_with_conditional(None, condition, block1, block2); + let condition = self.context.new_comparison(self.loc, ComparisonOp::LessThan, self.high(lhs), self.high(rhs)); + self.llbb().end_with_conditional(self.loc, condition, block1, block2); - block1.add_assignment(None, result, self.context.new_rvalue_zero(self.int_type)); - block1.end_with_jump(None, after); + block1.add_assignment(self.loc, result, self.context.new_rvalue_zero(self.int_type)); + block1.end_with_jump(self.loc, after); - let condition = self.context.new_comparison(None, ComparisonOp::GreaterThan, self.high(lhs), self.high(rhs)); - block2.end_with_conditional(None, condition, block3, block4); + let condition = self.context.new_comparison(self.loc, ComparisonOp::GreaterThan, self.high(lhs), self.high(rhs)); + block2.end_with_conditional(self.loc, condition, block3, block4); - block3.add_assignment(None, result, self.context.new_rvalue_from_int(self.int_type, 2)); - block3.end_with_jump(None, after); + block3.add_assignment(self.loc, result, self.context.new_rvalue_from_int(self.int_type, 2)); + block3.end_with_jump(self.loc, after); - let condition = self.context.new_comparison(None, ComparisonOp::LessThan, lhs_low, rhs_low); - block4.end_with_conditional(None, condition, block5, block6); + let condition = self.context.new_comparison(self.loc, ComparisonOp::LessThan, lhs_low, rhs_low); + block4.end_with_conditional(self.loc, condition, block5, block6); - block5.add_assignment(None, result, self.context.new_rvalue_zero(self.int_type)); - block5.end_with_jump(None, after); + block5.add_assignment(self.loc, result, self.context.new_rvalue_zero(self.int_type)); + block5.end_with_jump(self.loc, after); - let condition = self.context.new_comparison(None, ComparisonOp::GreaterThan, lhs_low, rhs_low); - block6.end_with_conditional(None, condition, block7, block8); + let condition = self.context.new_comparison(self.loc, ComparisonOp::GreaterThan, lhs_low, rhs_low); + block6.end_with_conditional(self.loc, condition, block7, block8); - block7.add_assignment(None, result, self.context.new_rvalue_from_int(self.int_type, 2)); - block7.end_with_jump(None, after); + block7.add_assignment(self.loc, result, self.context.new_rvalue_from_int(self.int_type, 2)); + block7.end_with_jump(self.loc, after); - block8.add_assignment(None, result, self.context.new_rvalue_one(self.int_type)); - block8.end_with_jump(None, after); + block8.add_assignment(self.loc, result, self.context.new_rvalue_one(self.int_type)); + block8.end_with_jump(self.loc, after); // NOTE: since jumps were added in a place rustc does not expect, the current block in the // state need to be updated. @@ -451,10 +451,10 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let (op, limit) = match op { IntPredicate::IntEQ => { - return self.context.new_comparison(None, ComparisonOp::Equals, cmp, self.context.new_rvalue_one(self.int_type)); + return self.context.new_comparison(self.loc, ComparisonOp::Equals, cmp, self.context.new_rvalue_one(self.int_type)); }, IntPredicate::IntNE => { - return self.context.new_comparison(None, ComparisonOp::NotEquals, cmp, self.context.new_rvalue_one(self.int_type)); + return self.context.new_comparison(self.loc, ComparisonOp::NotEquals, cmp, self.context.new_rvalue_one(self.int_type)); }, // TODO(antoyo): cast to u128 for unsigned comparison. See below. IntPredicate::IntUGT => (ComparisonOp::Equals, 2), @@ -466,39 +466,39 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { IntPredicate::IntSLT => (ComparisonOp::Equals, 0), IntPredicate::IntSLE => (ComparisonOp::LessThanEquals, 1), }; - self.context.new_comparison(None, op, cmp, self.context.new_rvalue_from_int(self.int_type, limit)) + self.context.new_comparison(self.loc, op, cmp, self.context.new_rvalue_from_int(self.int_type, limit)) } else if a_type.get_pointee().is_some() && b_type.get_pointee().is_some() { // NOTE: gcc cannot compare pointers to different objects, but rustc does that, so cast them to usize. - lhs = self.context.new_bitcast(None, lhs, self.usize_type); - rhs = self.context.new_bitcast(None, rhs, self.usize_type); - self.context.new_comparison(None, op.to_gcc_comparison(), lhs, rhs) + lhs = self.context.new_bitcast(self.loc, lhs, self.usize_type); + rhs = self.context.new_bitcast(self.loc, rhs, self.usize_type); + self.context.new_comparison(self.loc, op.to_gcc_comparison(), lhs, rhs) } else { if a_type != b_type { // NOTE: because libgccjit cannot compare function pointers. if a_type.dyncast_function_ptr_type().is_some() && b_type.dyncast_function_ptr_type().is_some() { - lhs = self.context.new_cast(None, lhs, self.usize_type.make_pointer()); - rhs = self.context.new_cast(None, rhs, self.usize_type.make_pointer()); + lhs = self.context.new_cast(self.loc, lhs, self.usize_type.make_pointer()); + rhs = self.context.new_cast(self.loc, rhs, self.usize_type.make_pointer()); } // NOTE: hack because we try to cast a vector type to the same vector type. else if format!("{:?}", a_type) != format!("{:?}", b_type) { - rhs = self.context.new_cast(None, rhs, a_type); + rhs = self.context.new_cast(self.loc, rhs, a_type); } } match op { IntPredicate::IntUGT | IntPredicate::IntUGE | IntPredicate::IntULT | IntPredicate::IntULE => { if !a_type.is_vector() { let unsigned_type = a_type.to_unsigned(&self.cx); - lhs = self.context.new_cast(None, lhs, unsigned_type); - rhs = self.context.new_cast(None, rhs, unsigned_type); + lhs = self.context.new_cast(self.loc, lhs, unsigned_type); + rhs = self.context.new_cast(self.loc, rhs, unsigned_type); } }, // TODO(antoyo): we probably need to handle signed comparison for unsigned // integers. _ => (), } - self.context.new_comparison(None, op.to_gcc_comparison(), lhs, rhs) + self.context.new_comparison(self.loc, op.to_gcc_comparison(), lhs, rhs) } } @@ -528,12 +528,12 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { if a_native && b_native { // FIXME(antoyo): remove the casts when libgccjit can shift an unsigned number by an unsigned number. if a_type.is_unsigned(self) && b_type.is_signed(self) { - let a = self.context.new_cast(None, a, b_type); + let a = self.context.new_cast(self.loc, a, b_type); let result = a << b; - self.context.new_cast(None, result, a_type) + self.context.new_cast(self.loc, result, a_type) } else if a_type.is_signed(self) && b_type.is_unsigned(self) { - let b = self.context.new_cast(None, b, a_type); + let b = self.context.new_cast(self.loc, b, a_type); a << b } else { @@ -557,40 +557,40 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let b0_block = func.new_block("b0"); let actual_else_block = func.new_block("actual_else"); - let result = func.new_local(None, a_type, "shiftResult"); + let result = func.new_local(self.loc, a_type, "shiftResult"); let b = self.gcc_int_cast(b, native_int_type); let sixty_four = self.gcc_int(native_int_type, 64); let zero = self.gcc_zero(native_int_type); let condition = self.gcc_icmp(IntPredicate::IntNE, self.gcc_and(b, sixty_four), zero); - self.llbb().end_with_conditional(None, condition, then_block, else_block); + self.llbb().end_with_conditional(self.loc, condition, then_block, else_block); let array_value = self.from_low_high_rvalues(a_type, zero, self.low(a) << (b - sixty_four), ); - then_block.add_assignment(None, result, array_value); - then_block.end_with_jump(None, after_block); + then_block.add_assignment(self.loc, result, array_value); + then_block.end_with_jump(self.loc, after_block); let condition = self.gcc_icmp(IntPredicate::IntEQ, b, zero); - else_block.end_with_conditional(None, condition, b0_block, actual_else_block); + else_block.end_with_conditional(self.loc, condition, b0_block, actual_else_block); - b0_block.add_assignment(None, result, a); - b0_block.end_with_jump(None, after_block); + b0_block.add_assignment(self.loc, result, a); + b0_block.end_with_jump(self.loc, after_block); // NOTE: cast low to its unsigned type in order to perform a logical right shift. // TODO(antoyo): adjust this ^ comment. let unsigned_type = native_int_type.to_unsigned(&self.cx); - let casted_low = self.context.new_cast(None, self.low(a), unsigned_type); - let shift_value = self.context.new_cast(None, sixty_four - b, unsigned_type); - let high_low = self.context.new_cast(None, casted_low >> shift_value, native_int_type); + let casted_low = self.context.new_cast(self.loc, self.low(a), unsigned_type); + let shift_value = self.context.new_cast(self.loc, sixty_four - b, unsigned_type); + let high_low = self.context.new_cast(self.loc, casted_low >> shift_value, native_int_type); let array_value = self.from_low_high_rvalues(a_type, self.low(a) << b, (self.high(a) << b) | high_low, ); - actual_else_block.add_assignment(None, result, array_value); - actual_else_block.end_with_jump(None, after_block); + actual_else_block.add_assignment(self.loc, result, array_value); + actual_else_block.end_with_jump(self.loc, after_block); // NOTE: since jumps were added in a place rustc does not expect, the current block in the // state need to be updated. @@ -606,10 +606,10 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let native_int_type = arg_type.dyncast_array().expect("get element type"); let lsb = self.low(arg); let swapped_lsb = self.gcc_bswap(lsb, width / 2); - let swapped_lsb = self.context.new_cast(None, swapped_lsb, native_int_type); + let swapped_lsb = self.context.new_cast(self.loc, swapped_lsb, native_int_type); let msb = self.high(arg); let swapped_msb = self.gcc_bswap(msb, width / 2); - let swapped_msb = self.context.new_cast(None, swapped_msb, native_int_type); + let swapped_msb = self.context.new_cast(self.loc, swapped_msb, native_int_type); // NOTE: we also need to swap the two elements here, in addition to swapping inside // the elements themselves like done above. @@ -625,7 +625,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { if param_type != arg_type { arg = self.bitcast(arg, param_type); } - self.cx.context.new_call(None, bswap, &[arg]) + self.cx.context.new_call(self.loc, bswap, &[arg]) } } @@ -700,33 +700,33 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { } } - fn bitwise_operation(&self, operation: BinaryOp, a: RValue<'gcc>, mut b: RValue<'gcc>) -> RValue<'gcc> { + fn bitwise_operation(&self, operation: BinaryOp, a: RValue<'gcc>, mut b: RValue<'gcc>, loc: Option<Location<'gcc>>) -> RValue<'gcc> { let a_type = a.get_type(); let b_type = b.get_type(); let a_native = self.is_native_int_type_or_bool(a_type); let b_native = self.is_native_int_type_or_bool(b_type); if a_type.is_vector() && b_type.is_vector() { let b = self.bitcast_if_needed(b, a_type); - self.context.new_binary_op(None, operation, a_type, a, b) + self.context.new_binary_op(loc, operation, a_type, a, b) } else if a_native && b_native { if a_type != b_type { - b = self.context.new_cast(None, b, a_type); + b = self.context.new_cast(loc, b, a_type); } - self.context.new_binary_op(None, operation, a_type, a, b) + self.context.new_binary_op(loc, operation, a_type, a, b) } else { assert!(!a_native && !b_native, "both types should either be native or non-native for or operation"); let native_int_type = a_type.dyncast_array().expect("get element type"); self.from_low_high_rvalues(a_type, - self.context.new_binary_op(None, operation, native_int_type, self.low(a), self.low(b)), - self.context.new_binary_op(None, operation, native_int_type, self.high(a), self.high(b)), + self.context.new_binary_op(loc, operation, native_int_type, self.low(a), self.low(b)), + self.context.new_binary_op(loc, operation, native_int_type, self.high(a), self.high(b)), ) } } - pub fn gcc_or(&self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { - self.bitwise_operation(BinaryOp::BitwiseOr, a, b) + pub fn gcc_or(&self, a: RValue<'gcc>, b: RValue<'gcc>, loc: Option<Location<'gcc>>) -> RValue<'gcc> { + self.bitwise_operation(BinaryOp::BitwiseOr, a, b, loc) } // TODO(antoyo): can we use https://github.com/rust-lang/compiler-builtins/blob/master/src/int/mod.rs#L379 instead? diff --git a/src/intrinsic/mod.rs b/src/intrinsic/mod.rs index f162ef831b7..0849c6266f1 100644 --- a/src/intrinsic/mod.rs +++ b/src/intrinsic/mod.rs @@ -640,7 +640,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let new_low = self.gcc_int_cast(reversed_high, typ); let new_high = self.shl(self.gcc_int_cast(reversed_low, typ), sixty_four); - self.gcc_or(new_low, new_high) + self.gcc_or(new_low, new_high, self.loc) }, _ => { panic!("cannot bit reverse with width = {}", width); @@ -685,44 +685,44 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let first_elem = self.context.new_array_access(None, result, zero); let first_value = self.gcc_int_cast(self.context.new_call(None, clzll, &[high]), arg_type); self.llbb() - .add_assignment(None, first_elem, first_value); + .add_assignment(self.loc, first_elem, first_value); - let second_elem = self.context.new_array_access(None, result, one); - let cast = self.gcc_int_cast(self.context.new_call(None, clzll, &[low]), arg_type); + let second_elem = self.context.new_array_access(self.loc, result, one); + let cast = self.gcc_int_cast(self.context.new_call(self.loc, clzll, &[low]), arg_type); let second_value = self.add(cast, sixty_four); self.llbb() - .add_assignment(None, second_elem, second_value); + .add_assignment(self.loc, second_elem, second_value); - let third_elem = self.context.new_array_access(None, result, two); + let third_elem = self.context.new_array_access(self.loc, result, two); let third_value = self.const_uint(arg_type, 128); self.llbb() - .add_assignment(None, third_elem, third_value); + .add_assignment(self.loc, third_elem, third_value); - let not_high = self.context.new_unary_op(None, UnaryOp::LogicalNegate, self.u64_type, high); - let not_low = self.context.new_unary_op(None, UnaryOp::LogicalNegate, self.u64_type, low); + let not_high = self.context.new_unary_op(self.loc, UnaryOp::LogicalNegate, self.u64_type, high); + let not_low = self.context.new_unary_op(self.loc, UnaryOp::LogicalNegate, self.u64_type, low); let not_low_and_not_high = not_low & not_high; let index = not_high + not_low_and_not_high; // NOTE: the following cast is necessary to avoid a GIMPLE verification failure in // gcc. // TODO(antoyo): do the correct verification in libgccjit to avoid an error at the // compilation stage. - let index = self.context.new_cast(None, index, self.i32_type); + let index = self.context.new_cast(self.loc, index, self.i32_type); - let res = self.context.new_array_access(None, result, index); + let res = self.context.new_array_access(self.loc, result, index); return self.gcc_int_cast(res.to_rvalue(), arg_type); } else { let count_leading_zeroes = self.context.get_builtin_function("__builtin_clzll"); - let arg = self.context.new_cast(None, arg, self.ulonglong_type); + let arg = self.context.new_cast(self.loc, arg, self.ulonglong_type); let diff = self.ulonglong_type.get_size() as i64 - arg_type.get_size() as i64; let diff = self.context.new_rvalue_from_long(self.int_type, diff * 8); - let res = self.context.new_call(None, count_leading_zeroes, &[arg]) - diff; - return self.context.new_cast(None, res, arg_type); + let res = self.context.new_call(self.loc, count_leading_zeroes, &[arg]) - diff; + return self.context.new_cast(self.loc, res, arg_type); }; let count_leading_zeroes = self.context.get_builtin_function(count_leading_zeroes); - let res = self.context.new_call(None, count_leading_zeroes, &[arg]); - self.context.new_cast(None, res, arg_type) + let res = self.context.new_call(self.loc, count_leading_zeroes, &[arg]); + self.context.new_cast(self.loc, res, arg_type) } fn count_trailing_zeroes(&mut self, _width: u64, arg: RValue<'gcc>) -> RValue<'gcc> { @@ -766,58 +766,58 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let ctzll = self.context.get_builtin_function("__builtin_ctzll"); - let first_elem = self.context.new_array_access(None, result, zero); - let first_value = self.gcc_int_cast(self.context.new_call(None, ctzll, &[low]), arg_type); + let first_elem = self.context.new_array_access(self.loc, result, zero); + let first_value = self.gcc_int_cast(self.context.new_call(self.loc, ctzll, &[low]), arg_type); self.llbb() - .add_assignment(None, first_elem, first_value); + .add_assignment(self.loc, first_elem, first_value); - let second_elem = self.context.new_array_access(None, result, one); - let second_value = self.gcc_add(self.gcc_int_cast(self.context.new_call(None, ctzll, &[high]), arg_type), sixty_four); + let second_elem = self.context.new_array_access(self.loc, result, one); + let second_value = self.gcc_add(self.gcc_int_cast(self.context.new_call(self.loc, ctzll, &[high]), arg_type), sixty_four); self.llbb() - .add_assignment(None, second_elem, second_value); + .add_assignment(self.loc, second_elem, second_value); - let third_elem = self.context.new_array_access(None, result, two); + let third_elem = self.context.new_array_access(self.loc, result, two); let third_value = self.gcc_int(arg_type, 128); self.llbb() - .add_assignment(None, third_elem, third_value); + .add_assignment(self.loc, third_elem, third_value); - let not_low = self.context.new_unary_op(None, UnaryOp::LogicalNegate, self.u64_type, low); - let not_high = self.context.new_unary_op(None, UnaryOp::LogicalNegate, self.u64_type, high); + let not_low = self.context.new_unary_op(self.loc, UnaryOp::LogicalNegate, self.u64_type, low); + let not_high = self.context.new_unary_op(self.loc, UnaryOp::LogicalNegate, self.u64_type, high); let not_low_and_not_high = not_low & not_high; let index = not_low + not_low_and_not_high; // NOTE: the following cast is necessary to avoid a GIMPLE verification failure in // gcc. // TODO(antoyo): do the correct verification in libgccjit to avoid an error at the // compilation stage. - let index = self.context.new_cast(None, index, self.i32_type); + let index = self.context.new_cast(self.loc, index, self.i32_type); - let res = self.context.new_array_access(None, result, index); + let res = self.context.new_array_access(self.loc, result, index); return self.gcc_int_cast(res.to_rvalue(), result_type); } else { let count_trailing_zeroes = self.context.get_builtin_function("__builtin_ctzll"); let arg_size = arg_type.get_size(); - let casted_arg = self.context.new_cast(None, arg, self.ulonglong_type); + let casted_arg = self.context.new_cast(self.loc, arg, self.ulonglong_type); let byte_diff = self.ulonglong_type.get_size() as i64 - arg_size as i64; let diff = self.context.new_rvalue_from_long(self.int_type, byte_diff * 8); let mask = self.context.new_rvalue_from_long(arg_type, -1); // To get the value with all bits set. - let masked = mask & self.context.new_unary_op(None, UnaryOp::BitwiseNegate, arg_type, arg); - let cond = self.context.new_comparison(None, ComparisonOp::Equals, masked, mask); - let diff = diff * self.context.new_cast(None, cond, self.int_type); - let res = self.context.new_call(None, count_trailing_zeroes, &[casted_arg]) - diff; - return self.context.new_cast(None, res, result_type); + let masked = mask & self.context.new_unary_op(self.loc, UnaryOp::BitwiseNegate, arg_type, arg); + let cond = self.context.new_comparison(self.loc, ComparisonOp::Equals, masked, mask); + let diff = diff * self.context.new_cast(self.loc, cond, self.int_type); + let res = self.context.new_call(self.loc, count_trailing_zeroes, &[casted_arg]) - diff; + return self.context.new_cast(self.loc, res, result_type); }; let count_trailing_zeroes = self.context.get_builtin_function(count_trailing_zeroes); let arg = if arg_type != expected_type { - self.context.new_cast(None, arg, expected_type) + self.context.new_cast(self.loc, arg, expected_type) } else { arg }; - let res = self.context.new_call(None, count_trailing_zeroes, &[arg]); - self.context.new_cast(None, res, result_type) + let res = self.context.new_call(self.loc, count_trailing_zeroes, &[arg]); + self.context.new_cast(self.loc, res, result_type) } fn pop_count(&mut self, value: RValue<'gcc>) -> RValue<'gcc> { @@ -859,8 +859,8 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let counter = self.current_func().new_local(None, counter_type, "popcount_counter"); let val = self.current_func().new_local(None, value_type, "popcount_value"); let zero = self.gcc_zero(counter_type); - self.llbb().add_assignment(None, counter, zero); - self.llbb().add_assignment(None, val, value); + self.llbb().add_assignment(self.loc, counter, zero); + self.llbb().add_assignment(self.loc, val, value); self.br(loop_head); // check if value isn't zero @@ -874,12 +874,12 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let one = self.gcc_int(value_type, 1); let sub = self.gcc_sub(val.to_rvalue(), one); let op = self.gcc_and(val.to_rvalue(), sub); - loop_body.add_assignment(None, val, op); + loop_body.add_assignment(self.loc, val, op); // counter += 1 let one = self.gcc_int(counter_type, 1); let op = self.gcc_add(counter.to_rvalue(), one); - loop_body.add_assignment(None, counter, op); + loop_body.add_assignment(self.loc, counter, op); self.br(loop_head); // end of loop @@ -922,7 +922,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { if signed { // Based on algorithm from: https://stackoverflow.com/a/56531252/389119 let func = self.current_func.borrow().expect("func"); - let res = func.new_local(None, result_type, "saturating_sum"); + let res = func.new_local(self.loc, result_type, "saturating_sum"); let supports_native_type = self.is_native_int_type(result_type); let overflow = if supports_native_type { @@ -936,7 +936,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { _ => unreachable!(), }; let overflow_func = self.context.get_builtin_function(func_name); - self.overflow_call(overflow_func, &[lhs, rhs, res.get_address(None)], None) + self.overflow_call(overflow_func, &[lhs, rhs, res.get_address(self.loc)], None) } else { let func_name = @@ -945,7 +945,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { _ => unreachable!(), }; let (int_result, overflow) = self.operation_with_overflow(func_name, lhs, rhs); - self.llbb().add_assignment(None, res, int_result); + self.llbb().add_assignment(self.loc, res, int_result); overflow }; @@ -958,10 +958,10 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let shifted = self.gcc_lshr(self.gcc_int_cast(lhs, unsigned_type), self.gcc_int(unsigned_type, width as i64 - 1)); let uint_max = self.gcc_not(self.gcc_int(unsigned_type, 0)); let int_max = self.gcc_lshr(uint_max, self.gcc_int(unsigned_type, 1)); - then_block.add_assignment(None, res, self.gcc_int_cast(self.gcc_add(shifted, int_max), result_type)); - then_block.end_with_jump(None, after_block); + then_block.add_assignment(self.loc, res, self.gcc_int_cast(self.gcc_add(shifted, int_max), result_type)); + then_block.end_with_jump(self.loc, after_block); - self.llbb().end_with_conditional(None, overflow, then_block, after_block); + self.llbb().end_with_conditional(self.loc, overflow, then_block, after_block); // NOTE: since jumps were added in a place rustc does not // expect, the current block in the state need to be updated. @@ -974,7 +974,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let res = self.gcc_add(lhs, rhs); let cond = self.gcc_icmp(IntPredicate::IntULT, res, lhs); let value = self.gcc_neg(self.gcc_int_cast(cond, result_type)); - self.gcc_or(res, value) + self.gcc_or(res, value, self.loc) } } @@ -984,7 +984,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { if signed { // Based on algorithm from: https://stackoverflow.com/a/56531252/389119 let func = self.current_func.borrow().expect("func"); - let res = func.new_local(None, result_type, "saturating_diff"); + let res = func.new_local(self.loc, result_type, "saturating_diff"); let supports_native_type = self.is_native_int_type(result_type); let overflow = if supports_native_type { @@ -998,7 +998,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { _ => unreachable!(), }; let overflow_func = self.context.get_builtin_function(func_name); - self.overflow_call(overflow_func, &[lhs, rhs, res.get_address(None)], None) + self.overflow_call(overflow_func, &[lhs, rhs, res.get_address(self.loc)], None) } else { let func_name = @@ -1007,7 +1007,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { _ => unreachable!(), }; let (int_result, overflow) = self.operation_with_overflow(func_name, lhs, rhs); - self.llbb().add_assignment(None, res, int_result); + self.llbb().add_assignment(self.loc, res, int_result); overflow }; @@ -1020,10 +1020,10 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let shifted = self.gcc_lshr(self.gcc_int_cast(lhs, unsigned_type), self.gcc_int(unsigned_type, width as i64 - 1)); let uint_max = self.gcc_not(self.gcc_int(unsigned_type, 0)); let int_max = self.gcc_lshr(uint_max, self.gcc_int(unsigned_type, 1)); - then_block.add_assignment(None, res, self.gcc_int_cast(self.gcc_add(shifted, int_max), result_type)); - then_block.end_with_jump(None, after_block); + then_block.add_assignment(self.loc, res, self.gcc_int_cast(self.gcc_add(shifted, int_max), result_type)); + then_block.end_with_jump(self.loc, after_block); - self.llbb().end_with_conditional(None, overflow, then_block, after_block); + self.llbb().end_with_conditional(self.loc, overflow, then_block, after_block); // NOTE: since jumps were added in a place rustc does not // expect, the current block in the state need to be updated. diff --git a/src/lib.rs b/src/lib.rs index 7f0696740b3..1c1f82c3221 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -39,6 +39,7 @@ extern crate rustc_errors; extern crate rustc_fluent_macro; extern crate rustc_fs_util; extern crate rustc_hir; +extern crate rustc_index; #[cfg(feature="master")] extern crate rustc_interface; extern crate rustc_macros; |
