@@ -253,6 +253,10 @@ struct arcv_apex_builtin_description {
253
253
/* Specifies the instruction format. See "apex_insn_format" enum
254
254
for more details. */
255
255
unsigned int insn_formats;
256
+
257
+ /* Suffix added to the instruction name when the format is resolved
258
+ (e.g., XS, XI, or XC); set to "i" if resolved, otherwise "". */
259
+ const char *insn_suffix;
256
260
};
257
261
258
262
/* The XD-type has 8 function bits encoding up to 256 instructions.
@@ -382,6 +386,73 @@ riscv_expand_builtin_insn (enum insn_code icode, unsigned int n_ops,
382
386
return has_target_p ? ops[0 ].value : const0_rtx;
383
387
}
384
388
389
+ /* Validate the immediate argument passed to an APEX intrinsic.
390
+
391
+ This function checks if the argument to the intrinsic call is a constant
392
+ integer and fits within the required immediate range depending on the
393
+ format supported by the given SUBCODE. Only instructions that do not
394
+ support APEX_XD are validated here.
395
+
396
+ - For APEX_XI and APEX_XC formats: the argument must be a
397
+ signed 12-bit integer.
398
+ - For APEX_XS format: the argument must be a signed 8-bit integer.
399
+
400
+ Returns false and reports an error if the argument is invalid; true
401
+ otherwise. */
402
+
403
+ static bool
404
+ arcv_apex_immediate_argument_valid_p (unsigned int subcode, tree exp)
405
+ {
406
+ if (!arcv_apex_format_supports_p (subcode, APEX_XD))
407
+ {
408
+ tree arg;
409
+ /* Get the first (and only) argument passed to the intrinsic call. */
410
+ if (arcv_apex_format_supports_p (subcode, APEX_XI))
411
+ arg = CALL_EXPR_ARG (exp, 0 );
412
+ else if (arcv_apex_format_supports_p (subcode, APEX_XC)
413
+ || arcv_apex_format_supports_p (subcode, APEX_XS))
414
+ arg = CALL_EXPR_ARG (exp, 1 );
415
+
416
+ /* If the argument is NOT a constant integer. */
417
+ if (!TREE_CONSTANT (arg) || TREE_CODE (arg) != INTEGER_CST)
418
+ {
419
+ error (" argument to %qs must be a constant integer" ,
420
+ arcv_apex_builtins[subcode].name );
421
+ return false ;
422
+ }
423
+
424
+ /* If the current subcode supports the APEX_XI or APEX_XC format, then
425
+ the operand must fit within a signed 12-bit immediate. */
426
+ if (arcv_apex_format_supports_p (subcode, APEX_XI)
427
+ || arcv_apex_format_supports_p (subcode, APEX_XC))
428
+ {
429
+ HOST_WIDE_INT val = tree_to_shwi (arg);
430
+ /* Check if the value fits within a signed 12-bit immediate. */
431
+ if ((val < -2048 || val > 2047 ))
432
+ {
433
+ error (" argument value %d is outside the valid range [-2048, 2047]" ,
434
+ val);
435
+ return false ;
436
+ }
437
+ }
438
+
439
+ /* If the current subcode supports the APEX_XS format, then
440
+ the operand must fit within a signed 8-bit immediate. */
441
+ if (arcv_apex_format_supports_p (subcode, APEX_XS))
442
+ {
443
+ HOST_WIDE_INT val = tree_to_shwi (arg);
444
+ /* Check if the value fits within a signed 8-bit immediate. */
445
+ if ((val < -128 || val > 127 ))
446
+ {
447
+ error (" argument value %d is outside the valid range [-128, 127]" ,
448
+ val);
449
+ return false ;
450
+ }
451
+ }
452
+ }
453
+ return true ;
454
+ }
455
+
385
456
/* Expand a RISCV_BUILTIN_DIRECT or RISCV_BUILTIN_DIRECT_NO_TARGET function;
386
457
HAS_TARGET_P says which. EXP is the CALL_EXPR that calls the function
387
458
and ICODE is the code of the associated .md pattern. TARGET, if nonnull,
@@ -405,6 +476,9 @@ riscv_expand_builtin_direct (enum insn_code icode, rtx target, tree exp,
405
476
rtx const_rtx = GEN_INT (subcode);
406
477
/* Add the subcode as an additional input operand to the RTL expression. */
407
478
create_input_operand (&ops[opno++], const_rtx, SImode);
479
+ /* Validate the immediate argument passed to the APEX intrinsic. */
480
+ if (!arcv_apex_immediate_argument_valid_p (subcode, exp))
481
+ return const0_rtx;
408
482
}
409
483
410
484
/* Map the arguments to the other operands. */
@@ -528,6 +602,18 @@ arcv_apex_get_insn_name (rtx op)
528
602
return arcv_apex_builtins[subcode].insn_name ;
529
603
}
530
604
605
+ /* Return the instruction suffix for an APEX subcode operand.
606
+
607
+ This suffix is used to mark instructions whose format was resolved
608
+ (e.g., XS, XI, or XC) rather than explicitly specified via pragma. */
609
+
610
+ const char *
611
+ arcv_apex_get_insn_suffix (rtx op)
612
+ {
613
+ unsigned int subcode = UINTVAL (op);
614
+ return arcv_apex_builtins[subcode].insn_suffix ;
615
+ }
616
+
531
617
/* Checks if the APEX builtin instruction identified by the subcode
532
618
supports the given instruction format.
533
619
@@ -646,10 +732,6 @@ arcv_apex_set_insn_operand_flags (unsigned int insn_format, tree fndecl)
646
732
static unsigned int
647
733
arcv_apex_resolve_insn_format (unsigned int insn_format, unsigned int opcode)
648
734
{
649
- /* Return early if a instruction format was defined by the used. */
650
- if ((insn_format & 0xF ) != APEX_NONE)
651
- return insn_format;
652
-
653
735
/* Extract the operand flags (DEST, SRC0, SRC1) from bits 5–7.
654
736
These bits encode the operand signature used for format selection. */
655
737
unsigned int insn_operands = insn_format >> 5 ;
@@ -863,15 +945,21 @@ arcv_apex_init_builtin (tree fndecl, const char *fn_name,
863
945
864
946
/* Resolve the instruction format:
865
947
If the user did not specify an instruction format at pragma level,
866
- infer the concrete format based on opcode and operand flags; otherwise,
867
- leave it as is. */
868
- insn_formats = arcv_apex_resolve_insn_format (insn_formats, opcode);
948
+ infer the concrete format based on opcode and operand flags. Mark
949
+ the insn. name with an "i" suffix for resolved XS/XI/XC formats;
950
+ otherwise, leave it as is. */
951
+ const char *insn_suffix = " " ;
952
+ if ((insn_formats & 0xF ) == APEX_NONE)
953
+ {
954
+ insn_formats = arcv_apex_resolve_insn_format (insn_formats, opcode);
955
+ insn_suffix = " i" ;
956
+ }
869
957
870
958
/* Validate the format is allowed for this instruction. */
871
959
arcv_apex_validate_insn_format (fn_name, insn_formats, opcode);
872
960
873
961
/* Print .extInstruction section about APEX instruction. */
874
- arcv_apex_print_insn_section (insn_name, opcode, insn_formats);
962
+ arcv_apex_print_insn_section (insn_name, insn_suffix, opcode, insn_formats);
875
963
876
964
/* Determine the internal instruction code (icode). */
877
965
enum insn_code icode = arcv_apex_get_icode (insn_formats);
@@ -883,7 +971,7 @@ arcv_apex_init_builtin (tree fndecl, const char *fn_name,
883
971
884
972
/* Store APEX insn information. */
885
973
arcv_apex_builtins[arcv_apex_builtin_index]
886
- = { icode, fn_name, insn_name, builtin_type, insn_formats };
974
+ = { icode, fn_name, insn_name, builtin_type, insn_formats, insn_suffix };
887
975
888
976
/* Modify the prototype type as built-in. */
889
977
fndecl->function_decl .built_in_class = BUILT_IN_MD;
0 commit comments