@@ -23721,6 +23721,16 @@ pub(super) fn is_elemental_math_intrinsic(name: &str) -> bool { |
| 23721 | 23721 | | "logical" | "conjg" | "aimag" | "dimag" |
| 23722 | 23722 | | "mod" | "modulo" | "sign" | "dim" | "max" | "min" |
| 23723 | 23723 | | "ichar" | "iachar" | "achar" | "char" |
| 23724 | + // F2018 §17.11 IEEE elemental intrinsics from `ieee_arithmetic`. |
| 23725 | + // Without this dispatch, `ieee_is_nan(arr)` falls through to the |
| 23726 | + // scalar `lower_intrinsic` arm which emits `fcmp ne desc, desc` |
| 23727 | + // on the array's descriptor pointer — garbage that downstream |
| 23728 | + // either rejects (IR verifier, "fcmp on non-float") or lets |
| 23729 | + // through silently to corrupt the next allocaed slot. stdlib |
| 23730 | + // hits this in the rank-N branch of `median_all_*` (`if any( |
| 23731 | + // ieee_is_nan(x))`) for `median`, `cov`, `sort_*`, etc. |
| 23732 | + | "ieee_is_nan" | "ieee_is_finite" | "ieee_is_negative" |
| 23733 | + | "ieee_is_normal" | "ieee_signbit" | "ieee_value" |
| 23724 | 23734 | // F2018 §16.9 character elementals — scalar form is already |
| 23725 | 23735 | // wired in lower_intrinsic; flagging them here lets reductions |
| 23726 | 23736 | // like `sum(len_trim(strs))` materialize the per-element |
@@ -24190,22 +24200,30 @@ pub(super) fn lower_rank1_elemental_call_descriptor( |
| 24190 | 24200 | | crate::sema::symtab::TypeInfo::Class(_) => return None, |
| 24191 | 24201 | other => (type_info_to_ir_type(&other), None), |
| 24192 | 24202 | }; |
| 24193 | | - let one_dim = b.const_i32(1); |
| 24194 | | - let lower = b.call( |
| 24195 | | - FuncRef::External("afs_array_lbound".into()), |
| 24196 | | - vec![control_desc, one_dim], |
| 24197 | | - IrType::Int(IntWidth::I64), |
| 24198 | | - ); |
| 24199 | | - let upper = b.call( |
| 24200 | | - FuncRef::External("afs_array_ubound".into()), |
| 24201 | | - vec![control_desc, one_dim], |
| 24202 | | - IrType::Int(IntWidth::I64), |
| 24203 | | - ); |
| 24203 | + // F2018 §16.9: an elemental call yields a result of the SAME SHAPE |
| 24204 | + // (rank + per-dim extents) as the array actuals. The previous |
| 24205 | + // rank-1-only allocator collapsed rank-N actuals to dim 1's |
| 24206 | + // extent, so a `(2,3)` source produced a 2-element mask and the |
| 24207 | + // remaining four elements wrote past the buffer. Use the |
| 24208 | + // same-shape allocator so callees see the full rank-N descriptor. |
| 24204 | 24209 | let elem_size = result_char_len |
| 24205 | 24210 | .map(|len| b.const_i64(len)) |
| 24206 | 24211 | .unwrap_or_else(|| b.const_i64(ir_scalar_byte_size(&result_elem_ty))); |
| 24207 | | - let result_desc = |
| 24208 | | - allocate_rank1_array_descriptor_with_runtime_bounds(b, lower, upper, elem_size); |
| 24212 | + let result_desc = b.alloca(IrType::Array(Box::new(IrType::Int(IntWidth::I8)), 384)); |
| 24213 | + let zero32_for_alloc = b.const_i32(0); |
| 24214 | + let sz384 = b.const_i64(384); |
| 24215 | + b.call( |
| 24216 | + FuncRef::External("memset".into()), |
| 24217 | + vec![result_desc, zero32_for_alloc, sz384], |
| 24218 | + IrType::Ptr(Box::new(IrType::Int(IntWidth::I8))), |
| 24219 | + ); |
| 24220 | + let stat_for_alloc = b.alloca(IrType::Int(IntWidth::I32)); |
| 24221 | + b.store(zero32_for_alloc, stat_for_alloc); |
| 24222 | + b.call( |
| 24223 | + FuncRef::External("afs_allocate_like_with_elem_size".into()), |
| 24224 | + vec![result_desc, control_desc, elem_size, stat_for_alloc], |
| 24225 | + IrType::Void, |
| 24226 | + ); |
| 24209 | 24227 | |
| 24210 | 24228 | let n = b.call( |
| 24211 | 24229 | FuncRef::External("afs_array_size".into()), |