diff --git a/src/builder.rs b/src/builder.rs index f978ba3b7d0..0d5b534a1a2 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -80,15 +80,15 @@ impl EnumClone for AtomicOrdering { pub struct Builder<'a: 'gcc, 'gcc, 'tcx> { pub cx: &'a CodegenCx<'gcc, 'tcx>, - pub block: Option>, + pub block: Block<'gcc>, stack_var_count: Cell, } impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { - fn with_cx(cx: &'a CodegenCx<'gcc, 'tcx>) -> Self { + fn with_cx(cx: &'a CodegenCx<'gcc, 'tcx>, block: Block<'gcc>) -> Self { Builder { cx, - block: None, + block, stack_var_count: Cell::new(0), } } @@ -243,7 +243,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { } pub fn current_func(&self) -> Function<'gcc> { - self.block.expect("block").get_function() + self.block.get_function() } fn function_call(&mut self, func: RValue<'gcc>, args: &[RValue<'gcc>], _funclet: Option<&Funclet>) -> RValue<'gcc> { @@ -254,17 +254,16 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { // gccjit requires to use the result of functions, even when it's not used. // That's why we assign the result to a local or call add_eval(). let return_type = func.get_return_type(); - let current_block = self.current_block.borrow().expect("block"); let void_type = self.context.new_type::<()>(); - let current_func = current_block.get_function(); + 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 })); - current_block.add_assignment(None, result, self.cx.context.new_call(None, func, &args)); + self.block.add_assignment(None, result, self.cx.context.new_call(None, func, &args)); result.to_rvalue() } else { - current_block.add_eval(None, self.cx.context.new_call(None, func, &args)); + self.block.add_eval(None, self.cx.context.new_call(None, func, &args)); // Return dummy value when not having return value. self.context.new_rvalue_from_long(self.isize_type, 0) } @@ -277,9 +276,8 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { // That's why we assign the result to a local or call add_eval(). let gcc_func = func_ptr.get_type().dyncast_function_ptr_type().expect("function ptr"); let mut return_type = gcc_func.get_return_type(); - let current_block = self.current_block.borrow().expect("block"); let void_type = self.context.new_type::<()>(); - let current_func = current_block.get_function(); + let current_func = self.block.get_function(); // FIXME(antoyo): As a temporary workaround for unsupported LLVM intrinsics. if gcc_func.get_param_count() == 0 && format!("{:?}", func_ptr) == "__builtin_ia32_pmovmskb128" { @@ -289,20 +287,20 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { if return_type != void_type { unsafe { RETURN_VALUE_COUNT += 1 }; let result = current_func.new_local(None, return_type, &format!("ptrReturnValue{}", unsafe { RETURN_VALUE_COUNT })); - current_block.add_assignment(None, result, self.cx.context.new_call_through_ptr(None, func_ptr, &args)); + self.block.add_assignment(None, result, self.cx.context.new_call_through_ptr(None, func_ptr, &args)); result.to_rvalue() } else { if gcc_func.get_param_count() == 0 { // FIXME(antoyo): As a temporary workaround for unsupported LLVM intrinsics. - current_block.add_eval(None, self.cx.context.new_call_through_ptr(None, func_ptr, &[])); + self.block.add_eval(None, self.cx.context.new_call_through_ptr(None, func_ptr, &[])); } else { - current_block.add_eval(None, self.cx.context.new_call_through_ptr(None, func_ptr, &args)); + self.block.add_eval(None, self.cx.context.new_call_through_ptr(None, func_ptr, &args)); } // Return dummy value when not having return value. let result = current_func.new_local(None, self.isize_type, "dummyValueThatShouldNeverBeUsed"); - current_block.add_assignment(None, result, self.context.new_rvalue_from_long(self.isize_type, 0)); + self.block.add_assignment(None, result, self.context.new_rvalue_from_long(self.isize_type, 0)); result.to_rvalue() } } @@ -311,12 +309,11 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { // gccjit requires to use the result of functions, even when it's not used. // That's why we assign the result to a local. let return_type = self.context.new_type::(); - let current_block = self.current_block.borrow().expect("block"); - let current_func = current_block.get_function(); + 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 })); - current_block.add_assignment(None, result, self.cx.context.new_call(None, func, &args)); + self.block.add_assignment(None, result, self.cx.context.new_call(None, func, &args)); result.to_rvalue() } } @@ -382,14 +379,13 @@ impl<'gcc, 'tcx> BackendTypes for Builder<'_, 'gcc, 'tcx> { impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { fn build(cx: &'a CodegenCx<'gcc, 'tcx>, block: Block<'gcc>) -> Self { - let mut bx = Builder::with_cx(cx); + let bx = Builder::with_cx(cx, block); *cx.current_block.borrow_mut() = Some(block); - bx.block = Some(block); bx } fn llbb(&self) -> Block<'gcc> { - self.block.expect("block") + self.block } fn append_block(cx: &'a CodegenCx<'gcc, 'tcx>, func: RValue<'gcc>, name: &str) -> Block<'gcc> { @@ -404,7 +400,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { fn switch_to_block(&mut self, block: Self::BasicBlock) { *self.cx.current_block.borrow_mut() = Some(block); - self.block = Some(block); + self.block = block; } fn ret_void(&mut self) { @@ -439,7 +435,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.expect("block").end_with_switch(None, value, default_block, &gcc_cases); + self.block.end_with_switch(None, value, default_block, &gcc_cases); } fn invoke(&mut self, _typ: Type<'gcc>, _func: RValue<'gcc>, _args: &[RValue<'gcc>], then: Block<'gcc>, catch: Block<'gcc>, _funclet: Option<&Funclet>) -> RValue<'gcc> { @@ -452,17 +448,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"); - let block = self.block.expect("block"); - block.add_eval(None, self.context.new_call(None, func, &[])); - let return_type = block.get_function().get_return_type(); + self.block.add_eval(None, self.context.new_call(None, func, &[])); + let return_type = self.block.get_function().get_return_type(); let void_type = self.context.new_type::<()>(); if return_type == void_type { - block.end_with_void_return(None) + self.block.end_with_void_return(None) } else { let return_value = self.current_func() .new_local(None, return_type, "unreachableReturn"); - block.end_with_return(None, return_value) + self.block.end_with_return(None, return_value) } } @@ -909,11 +904,11 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { } fn ptrtoint(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> { - self.cx.ptrtoint(self.block.expect("block"), value, dest_ty) + self.cx.ptrtoint(self.block, value, dest_ty) } fn inttoptr(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> { - self.cx.inttoptr(self.block.expect("block"), value, dest_ty) + self.cx.inttoptr(self.block, value, dest_ty) } fn bitcast(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> { @@ -965,9 +960,8 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { let dst = self.pointercast(dst, self.type_i8p()); let src = self.pointercast(src, self.type_ptr_to(self.type_void())); let memcpy = self.context.get_builtin_function("memcpy"); - let block = self.block.expect("block"); // TODO(antoyo): handle aligns and is_volatile. - block.add_eval(None, self.context.new_call(None, memcpy, &[dst, src, size])); + self.block.add_eval(None, self.context.new_call(None, 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) { @@ -984,20 +978,18 @@ 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 memmove = self.context.get_builtin_function("memmove"); - let block = self.block.expect("block"); // TODO(antoyo): handle is_volatile. - block.add_eval(None, self.context.new_call(None, memmove, &[dst, src, size])); + self.block.add_eval(None, self.context.new_call(None, memmove, &[dst, src, size])); } fn memset(&mut self, ptr: RValue<'gcc>, fill_byte: RValue<'gcc>, size: RValue<'gcc>, _align: Align, flags: MemFlags) { let _is_volatile = flags.contains(MemFlags::VOLATILE); let ptr = self.pointercast(ptr, self.type_i8p()); let memset = self.context.get_builtin_function("memset"); - let block = self.block.expect("block"); // TODO(antoyo): handle align and is_volatile. let fill_byte = self.context.new_cast(None, fill_byte, self.i32_type); let size = self.intcast(size, self.type_size_t(), false); - block.add_eval(None, self.context.new_call(None, memset, &[ptr, fill_byte, size])); + self.block.add_eval(None, self.context.new_call(None, memset, &[ptr, fill_byte, size])); } fn select(&mut self, cond: RValue<'gcc>, then_val: RValue<'gcc>, mut else_val: RValue<'gcc>) -> RValue<'gcc> {