fortrangoingonforty/armfortas / 9989fa5

Browse files

Preserve narrow VALUE call widths

Authored by espadonne
SHA
9989fa5f69b0e4a58b345099f882380bb21f43e4
Parents
ea1a9b7
Tree
c2e66d0

2 changed files

StatusFile+-
M src/ir/lower.rs 35 9
M tests/calling_convention_runtime.rs 82 0
src/ir/lower.rsmodified
@@ -8374,6 +8374,24 @@ fn callee_arg_symbol<'a>(
83748374
     scope.symbols.get(arg_name)
83758375
 }
83768376
 
8377
+fn callee_arg_ir_type(st: &SymbolTable, callee_name: &str, idx: usize) -> Option<IrType> {
8378
+    callee_arg_symbol(st, callee_name, idx)
8379
+        .and_then(|sym| sym.type_info.as_ref())
8380
+        .map(type_info_to_ir_type)
8381
+}
8382
+
8383
+fn coerce_value_call_arg(
8384
+    b: &mut FuncBuilder,
8385
+    st: &SymbolTable,
8386
+    callee_name: &str,
8387
+    idx: usize,
8388
+    raw: ValueId,
8389
+) -> ValueId {
8390
+    callee_arg_ir_type(st, callee_name, idx)
8391
+        .map(|ty| coerce_to_type(b, raw, &ty))
8392
+        .unwrap_or(raw)
8393
+}
8394
+
83778395
 fn zero_value_for_ir_type(b: &mut FuncBuilder, ty: &IrType) -> ValueId {
83788396
     match ty {
83798397
         IrType::Int(IntWidth::I64) => b.const_i64(0),
@@ -8399,9 +8417,7 @@ fn missing_optional_call_arg(
83998417
     if !is_value {
84008418
         return b.const_i64(0);
84018419
     }
8402
-    callee_arg_symbol(st, callee_name, idx)
8403
-        .and_then(|sym| sym.type_info.as_ref())
8404
-        .map(type_info_to_ir_type)
8420
+    callee_arg_ir_type(st, callee_name, idx)
84058421
         .map(|ty| zero_value_for_ir_type(b, &ty))
84068422
         .unwrap_or_else(|| b.const_i32(0))
84078423
 }
@@ -8726,7 +8742,7 @@ fn emit_named_function_call(
87268742
                         descriptor_params,
87278743
                     )
87288744
                 } else if is_value {
8729
-                    lower_expr_full(
8745
+                    let raw = lower_expr_full(
87308746
                         b,
87318747
                         locals,
87328748
                         e,
@@ -8735,7 +8751,8 @@ fn emit_named_function_call(
87358751
                         internal_funcs,
87368752
                         contained_host_refs,
87378753
                         descriptor_params,
8738
-                    )
8754
+                    );
8755
+                    coerce_value_call_arg(b, st, abi_primary_key, i, raw)
87398756
                 } else if wants_descriptor {
87408757
                     lower_arg_descriptor(b, locals, e, st, type_layouts)
87418758
                 } else if wants_string_descriptor {
@@ -8982,7 +8999,8 @@ fn lower_alloc_return_call_into_desc(
89828999
                         Some(ctx.descriptor_params),
89839000
                     )
89849001
                 } else if is_value {
8985
-                    lower_expr_ctx(b, ctx, e)
9002
+                    let raw = lower_expr_ctx(b, ctx, e);
9003
+                    coerce_value_call_arg(b, ctx.st, abi_primary_key, i, raw)
89869004
                 } else if wants_string_descriptor {
89879005
                     lower_arg_string_descriptor(b, &ctx.locals, e, ctx.st, Some(ctx.type_layouts))
89889006
                 } else if wants_descriptor {
@@ -12674,7 +12692,7 @@ fn lower_stmt(b: &mut FuncBuilder, ctx: &mut LowerCtx, stmt: &SpannedStmt) {
1267412692
                                             Some(ctx.descriptor_params),
1267512693
                                         )
1267612694
                                     } else if is_value {
12677
-                                        lower_expr_full(
12695
+                                        let raw = lower_expr_full(
1267812696
                                             b,
1267912697
                                             &ctx.locals,
1268012698
                                             e,
@@ -12683,6 +12701,13 @@ fn lower_stmt(b: &mut FuncBuilder, ctx: &mut LowerCtx, stmt: &SpannedStmt) {
1268312701
                                             Some(ctx.internal_funcs),
1268412702
                                             Some(ctx.contained_host_refs),
1268512703
                                             Some(ctx.descriptor_params),
12704
+                                        );
12705
+                                        coerce_value_call_arg(
12706
+                                            b,
12707
+                                            ctx.st,
12708
+                                            abi_primary_key,
12709
+                                            i,
12710
+                                            raw,
1268612711
                                         )
1268712712
                                     } else if wants_descriptor {
1268812713
                                         lower_arg_descriptor(
@@ -23381,7 +23406,7 @@ fn lower_expr_full(
2338123406
                                         descriptor_params,
2338223407
                                     )
2338323408
                                 } else if is_value {
23384
-                                    lower_expr_full(
23409
+                                    let raw = lower_expr_full(
2338523410
                                         b,
2338623411
                                         locals,
2338723412
                                         e,
@@ -23390,7 +23415,8 @@ fn lower_expr_full(
2339023415
                                         internal_funcs,
2339123416
                                         contained_host_refs,
2339223417
                                         descriptor_params,
23393
-                                    )
23418
+                                    );
23419
+                                    coerce_value_call_arg(b, st, abi_primary_key, i, raw)
2339423420
                                 } else if wants_descriptor {
2339523421
                                     lower_arg_descriptor(b, locals, e, st, type_layouts)
2339623422
                                 } else if wants_string_descriptor {
tests/calling_convention_runtime.rsmodified
@@ -231,6 +231,88 @@ fn bind_c_ninth_float_arg_spills_with_integer_args_still_in_registers() {
231231
     let _ = std::fs::remove_dir_all(&dir);
232232
 }
233233
 
234
+#[test]
235
+fn bind_c_signed_char_value_args_keep_narrow_stack_widths() {
236
+    let dir = unique_dir("i8_stack");
237
+    let c_src = write_program_in(
238
+        &dir,
239
+        "check_i8_stack.c",
240
+        "#include <stdint.h>\n\nint check_i8_stack(int8_t a1, int8_t a2, int8_t a3, int8_t a4, int8_t a5, int8_t a6, int8_t a7, int8_t a8, int8_t a9, int8_t a10) {\n    if (a1 != 1) return 1;\n    if (a2 != 2) return 2;\n    if (a3 != 3) return 3;\n    if (a4 != 4) return 4;\n    if (a5 != 5) return 5;\n    if (a6 != 6) return 6;\n    if (a7 != 7) return 7;\n    if (a8 != 8) return 8;\n    if (a9 != 9) return 9;\n    if (a10 != 10) return 10;\n    return 19;\n}\n",
241
+    );
242
+    let c_obj = dir.join("check_i8_stack.o");
243
+    compile_c_object(&c_src, &c_obj);
244
+
245
+    let f_src = write_program_in(
246
+        &dir,
247
+        "main.f90",
248
+        "program p\n  use iso_c_binding, only: c_int, c_signed_char\n  implicit none\n  interface\n    function check_i8_stack(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) result(rc) bind(C, name='check_i8_stack')\n      import :: c_int, c_signed_char\n      integer(c_signed_char), value :: a1, a2, a3, a4, a5, a6, a7, a8, a9, a10\n      integer(c_int) :: rc\n    end function check_i8_stack\n  end interface\n  integer(c_int) :: rc\n\n  rc = check_i8_stack(1_c_signed_char, 2_c_signed_char, 3_c_signed_char, 4_c_signed_char, 5_c_signed_char, 6_c_signed_char, 7_c_signed_char, 8_c_signed_char, 9_c_signed_char, 10_c_signed_char)\n  if (rc /= 19_c_int) error stop rc\n  print *, 'ok'\nend program\n",
249
+    );
250
+    let f_obj = dir.join("main.o");
251
+    compile_fortran_object(&f_src, &f_obj);
252
+
253
+    let exe = dir.join("i8_stack.bin");
254
+    link_program(&[&f_obj, &c_obj], &exe);
255
+
256
+    let run = Command::new(&exe)
257
+        .output()
258
+        .expect("c_signed_char stack runtime failed");
259
+    assert!(
260
+        run.status.success(),
261
+        "c_signed_char stack runtime failed: status={:?}\nstdout:\n{}\nstderr:\n{}",
262
+        run.status,
263
+        String::from_utf8_lossy(&run.stdout),
264
+        String::from_utf8_lossy(&run.stderr)
265
+    );
266
+    assert!(
267
+        String::from_utf8_lossy(&run.stdout).contains("ok"),
268
+        "unexpected c_signed_char stack output: {}",
269
+        String::from_utf8_lossy(&run.stdout)
270
+    );
271
+
272
+    let _ = std::fs::remove_dir_all(&dir);
273
+}
274
+
275
+#[test]
276
+fn bind_c_short_value_args_keep_narrow_stack_widths() {
277
+    let dir = unique_dir("i16_stack");
278
+    let c_src = write_program_in(
279
+        &dir,
280
+        "check_i16_stack.c",
281
+        "#include <stdint.h>\n\nint check_i16_stack(int16_t a1, int16_t a2, int16_t a3, int16_t a4, int16_t a5, int16_t a6, int16_t a7, int16_t a8, int16_t a9, int16_t a10) {\n    if (a1 != 1) return 1;\n    if (a2 != 2) return 2;\n    if (a3 != 3) return 3;\n    if (a4 != 4) return 4;\n    if (a5 != 5) return 5;\n    if (a6 != 6) return 6;\n    if (a7 != 7) return 7;\n    if (a8 != 8) return 8;\n    if (a9 != 9) return 9;\n    if (a10 != 10) return 10;\n    return 19;\n}\n",
282
+    );
283
+    let c_obj = dir.join("check_i16_stack.o");
284
+    compile_c_object(&c_src, &c_obj);
285
+
286
+    let f_src = write_program_in(
287
+        &dir,
288
+        "main.f90",
289
+        "program p\n  use iso_c_binding, only: c_int, c_short\n  implicit none\n  interface\n    function check_i16_stack(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) result(rc) bind(C, name='check_i16_stack')\n      import :: c_int, c_short\n      integer(c_short), value :: a1, a2, a3, a4, a5, a6, a7, a8, a9, a10\n      integer(c_int) :: rc\n    end function check_i16_stack\n  end interface\n  integer(c_int) :: rc\n\n  rc = check_i16_stack(1_c_short, 2_c_short, 3_c_short, 4_c_short, 5_c_short, 6_c_short, 7_c_short, 8_c_short, 9_c_short, 10_c_short)\n  if (rc /= 19_c_int) error stop rc\n  print *, 'ok'\nend program\n",
290
+    );
291
+    let f_obj = dir.join("main.o");
292
+    compile_fortran_object(&f_src, &f_obj);
293
+
294
+    let exe = dir.join("i16_stack.bin");
295
+    link_program(&[&f_obj, &c_obj], &exe);
296
+
297
+    let run = Command::new(&exe)
298
+        .output()
299
+        .expect("c_short stack runtime failed");
300
+    assert!(
301
+        run.status.success(),
302
+        "c_short stack runtime failed: status={:?}\nstdout:\n{}\nstderr:\n{}",
303
+        run.status,
304
+        String::from_utf8_lossy(&run.stdout),
305
+        String::from_utf8_lossy(&run.stderr)
306
+    );
307
+    assert!(
308
+        String::from_utf8_lossy(&run.stdout).contains("ok"),
309
+        "unexpected c_short stack output: {}",
310
+        String::from_utf8_lossy(&run.stdout)
311
+    );
312
+
313
+    let _ = std::fs::remove_dir_all(&dir);
314
+}
315
+
234316
 #[test]
235317
 fn contained_hidden_result_optional_gap_preserves_host_and_char_ordering() {
236318
     let dir = unique_dir("contained_hidden_result_gap");