|
1 | | -use rustc_abi::{Align, BackendRepr, Endian, HasDataLayout, Primitive, Size}; |
| 1 | +use rustc_abi::{Align, BackendRepr, Endian, Float, HasDataLayout, Integer, Primitive, Size}; |
2 | 2 | use rustc_codegen_ssa::MemFlags; |
3 | 3 | use rustc_codegen_ssa::common::IntPredicate; |
4 | 4 | use rustc_codegen_ssa::mir::operand::OperandRef; |
@@ -33,7 +33,7 @@ fn round_pointer_up_to_alignment<'ll>( |
33 | 33 | bx.call_intrinsic( |
34 | 34 | "llvm.ptrmask", |
35 | 35 | &[ptr_ty, bx.type_i32()], |
36 | | - &[ptr, bx.const_int(bx.isize_ty, -(align.bytes() as isize) as i64)], |
| 36 | + &[ptr, bx.const_i32(-(align.bytes() as i32))], |
37 | 37 | ) |
38 | 38 | } |
39 | 39 |
|
@@ -75,6 +75,35 @@ fn emit_direct_ptr_va_arg<'ll, 'tcx>( |
75 | 75 | } |
76 | 76 | } |
77 | 77 |
|
| 78 | +/// Some backends apply special alignment rules to c-variadic arguments. |
| 79 | +fn get_param_type_alignment<'ll, 'tcx>( |
| 80 | + bx: &mut Builder<'_, 'll, 'tcx>, |
| 81 | + layout: TyAndLayout<'tcx>, |
| 82 | +) -> Align { |
| 83 | + let BackendRepr::Scalar(scalar) = layout.backend_repr else { |
| 84 | + bug!("unexpected backend repr {:?}", layout.backend_repr); |
| 85 | + }; |
| 86 | + |
| 87 | + match bx.cx.tcx.sess.target.arch { |
| 88 | + Arch::PowerPC64 => match scalar.primitive() { |
| 89 | + Primitive::Int(integer, _) => match integer { |
| 90 | + Integer::I8 | Integer::I16 => unreachable!(), |
| 91 | + Integer::I32 | Integer::I64 => { /* fall through */ } |
| 92 | + Integer::I128 => return Align::EIGHT, |
| 93 | + }, |
| 94 | + Primitive::Float(float) => match float { |
| 95 | + Float::F16 | Float::F32 => unreachable!(), |
| 96 | + Float::F64 => { /* fall through */ } |
| 97 | + Float::F128 => return Align::from_bytes(16).unwrap(), |
| 98 | + }, |
| 99 | + Primitive::Pointer(_) => { /* fall through */ } |
| 100 | + }, |
| 101 | + _ => { /* fall through */ } |
| 102 | + } |
| 103 | + |
| 104 | + layout.align.abi |
| 105 | +} |
| 106 | + |
78 | 107 | enum PassMode { |
79 | 108 | Direct, |
80 | 109 | Indirect, |
@@ -115,23 +144,23 @@ fn emit_ptr_va_arg<'ll, 'tcx>( |
115 | 144 | ( |
116 | 145 | bx.cx.layout_of(Ty::new_imm_ptr(bx.cx.tcx, target_ty)).llvm_type(bx.cx), |
117 | 146 | bx.cx.data_layout().pointer_size(), |
118 | | - bx.cx.data_layout().pointer_align(), |
| 147 | + bx.cx.data_layout().pointer_align().abi, |
119 | 148 | ) |
120 | 149 | } else { |
121 | | - (layout.llvm_type(bx.cx), layout.size, layout.align) |
| 150 | + (layout.llvm_type(bx.cx), layout.size, get_param_type_alignment(bx, layout)) |
122 | 151 | }; |
123 | 152 | let (addr, addr_align) = emit_direct_ptr_va_arg( |
124 | 153 | bx, |
125 | 154 | list, |
126 | 155 | size, |
127 | | - align.abi, |
| 156 | + align, |
128 | 157 | slot_size, |
129 | 158 | allow_higher_align, |
130 | 159 | force_right_adjust, |
131 | 160 | ); |
132 | 161 | if indirect { |
133 | 162 | let tmp_ret = bx.load(llty, addr, addr_align); |
134 | | - bx.load(layout.llvm_type(bx.cx), tmp_ret, align.abi) |
| 163 | + bx.load(layout.llvm_type(bx.cx), tmp_ret, align) |
135 | 164 | } else { |
136 | 165 | bx.load(llty, addr, addr_align) |
137 | 166 | } |
@@ -765,9 +794,16 @@ fn x86_64_sysv64_va_arg_from_memory<'ll, 'tcx>( |
765 | 794 | // byte boundary if alignment needed by type exceeds 8 byte boundary. |
766 | 795 | // It isn't stated explicitly in the standard, but in practice we use |
767 | 796 | // alignment greater than 16 where necessary. |
768 | | - if layout.layout.align.bytes() > 8 { |
769 | | - unreachable!("all instances of VaArgSafe have an alignment <= 8"); |
770 | | - } |
| 797 | + let overflow_arg_area_v = if layout.layout.align.bytes() > 8 { |
| 798 | + round_pointer_up_to_alignment( |
| 799 | + bx, |
| 800 | + overflow_arg_area_v, |
| 801 | + layout.layout.align.abi, |
| 802 | + bx.type_ptr(), |
| 803 | + ) |
| 804 | + } else { |
| 805 | + overflow_arg_area_v |
| 806 | + }; |
771 | 807 |
|
772 | 808 | // AMD64-ABI 3.5.7p5: Step 8. Fetch type from l->overflow_arg_area. |
773 | 809 | let mem_addr = overflow_arg_area_v; |
@@ -1075,6 +1111,7 @@ pub(super) fn emit_va_arg<'ll, 'tcx>( |
1075 | 1111 | PassMode::Direct, |
1076 | 1112 | SlotSize::Bytes8, |
1077 | 1113 | AllowHigherAlign::Yes, |
| 1114 | + // ForceRightAdjust only takes effect on big-endian architectures. |
1078 | 1115 | ForceRightAdjust::Yes, |
1079 | 1116 | ), |
1080 | 1117 | Arch::RiscV32 if target.llvm_abiname == LlvmAbi::Ilp32e => { |
|
0 commit comments