<s> void RISCVPassConfig :: addPreRegAlloc ( ) { addPass ( createRISCVMergeBaseOffsetOptPass ( ) ) ; if ( getOptLevel ( ) > CodeGenOpt :: None ) addPass ( createRISCVRemoveRedundancyVSETVLPass ( ) ) ; } </s>

This method may be implemented by targets that want to run passes immediately before register allocation .


<s> unsigned RISCVInstrInfo :: isLoadFromStackSlot ( const MachineInstr & MI , int & FrameIndex ) const { switch ( MI . getOpcode ( ) ) { default : return 0 ; case RISCV :: LB : case RISCV :: LBU : case RISCV :: LH : case RISCV :: LHU : case RISCV :: LW : case RISCV :: FLW : case RISCV :: LWU : case RISCV :: LD : case RISCV :: FLD : case RISCV :: VLE_V_um : break ; } if ( ( MI . getOpcode ( ) == RISCV :: VLE_V_um ) && MI . getOperand ( 1 ) . isFI ( ) ) { FrameIndex = MI . getOperand ( 1 ) . getIndex ( ) ; return MI . getOperand ( 0 ) . getReg ( ) ; } else if ( MI . getOperand ( 1 ) . isFI ( ) && MI . getOperand ( 2 ) . isImm ( ) && MI . getOperand ( 2 ) . getImm ( ) == 0 ) { FrameIndex = MI . getOperand ( 1 ) . getIndex ( ) ; return MI . getOperand ( 0 ) . getReg ( ) ; } return 0 ; } </s>

isLoadFromStackSlot - If the specified machine instruction is a direct load from a stack slot , return the virtual or physical register number of the destination along with the FrameIndex of the loaded stack slot .


<s> void getAnalysisUsage ( AnalysisUsage & AU ) const override { AU . setPreservesCFG ( ) ; MachineFunctionPass :: getAnalysisUsage ( AU ) ; } </s>

getAnalysisUsage - Subclasses that override getAnalysisUsage must call this .


<s> bool RISCVMCExpr :: evaluateAsConstant ( int64_t & Res ) const { MCValue Value ; if ( Kind == VK_RISCV_PCREL_HI || Kind == VK_RISCV_PCREL_LO || Kind == VK_RISCV_GOT_HI || Kind == VK_RISCV_TPREL_HI || Kind == VK_RISCV_TPREL_LO || Kind == VK_RISCV_TPREL_ADD || Kind == VK_RISCV_TLS_GOT_HI || Kind == VK_RISCV_TLS_GD_HI || Kind == VK_RISCV_CALL || Kind == VK_RISCV_CALL_PLT || Kind == VK_RISCV_CAPTAB_PCREL_HI || Kind == VK_RISCV_TPREL_CINCOFFSET || Kind == VK_RISCV_TLS_IE_CAPTAB_PCREL_HI || Kind == VK_RISCV_TLS_GD_CAPTAB_PCREL_HI || Kind == VK_RISCV_CCALL ) return false ; if ( ! getSubExpr ( ) -> evaluateAsRelocatable ( Value , nullptr , nullptr ) ) return false ; if ( ! Value . isAbsolute ( ) ) return false ; Res = evaluateAsInt64 ( Value . getConstant ( ) ) ; return true ; } </s>

Evaluates the fixup as a constant value .

RISCV RISCV RISCV RISCV RISCV RISCV RISCV RISCV RISCV RISCV RISCV RISCV RISCV RISCV RISCV RISCV RISCV


<s> RISCVSubtarget & RISCVSubtarget :: initializeSubtargetDependencies ( const Triple & TT , StringRef CPU , StringRef FS , StringRef ABIName ) { bool Is64Bit = TT . isArch64Bit ( ) ; std :: string CPUName = std :: string ( CPU ) ; if ( CPUName . empty ( ) ) CPUName = Is64Bit ? "generic-rv64" : "generic-rv32" ; ParseSubtargetFeatures ( CPUName , FS ) ; if ( Is64Bit ) { XLenVT = MVT :: i64 ; XLen = 64 ; } TargetABI = RISCVABI :: computeTargetABI ( TT , getFeatureBits ( ) , ABIName ) ; RISCVFeatures :: validate ( TT , getFeatureBits ( ) ) ; return * this ; } </s>

initializeSubtargetDependencies - Initializes using a CPU , a TuneCPU , and feature string so that we can use initializer lists for subtarget initialization .


<s> static void riscv_setup_incoming_varargs ( cumulative_args_t cum , enum machine_mode mode , tree type , int * pretend_size ATTRIBUTE_UNUSED , int no_rtl ) { CUMULATIVE_ARGS local_cum ; int gp_saved ; local_cum = * get_cumulative_args ( cum ) ; riscv_function_arg_advance ( pack_cumulative_args ( & local_cum ) , mode , type , 1 ) ; gp_saved = MAX_ARGS_IN_REGISTERS - local_cum . num_gprs ; if ( ! no_rtl && gp_saved > 0 ) { rtx ptr = plus_constant ( Pmode , virtual_incoming_args_rtx , REG_PARM_STACK_SPACE ( cfun -> decl ) - gp_saved * UNITS_PER_WORD ) ; rtx mem = gen_frame_mem ( BLKmode , ptr ) ; set_mem_alias_set ( mem , get_varargs_alias_set ( ) ) ; move_block_from_reg ( local_cum . num_gprs + GP_ARG_FIRST , mem , gp_saved ) ; } if ( REG_PARM_STACK_SPACE ( cfun -> decl ) == 0 ) cfun -> machine -> varargs_size = gp_saved * UNITS_PER_WORD ; } </s>


<s> bool riscv_expand_block_move ( rtx dest , rtx src , rtx length ) { if ( CONST_INT_P ( length ) ) { unsigned HOST_WIDE_INT hwi_length = UINTVAL ( length ) ; unsigned HOST_WIDE_INT factor , align ; align = MIN ( MIN ( MEM_ALIGN ( src ) , MEM_ALIGN ( dest ) ) , BITS_PER_WORD ) ; factor = BITS_PER_WORD / align ; if ( optimize_function_for_size_p ( cfun ) && hwi_length * factor * UNITS_PER_WORD > MOVE_RATIO ( false ) ) return false ; if ( hwi_length <= ( RISCV_MAX_MOVE_BYTES_STRAIGHT / factor ) ) { riscv_block_move_straight ( dest , src , INTVAL ( length ) ) ; return true ; } else if ( optimize && align >= BITS_PER_WORD ) { unsigned min_iter_words = RISCV_MAX_MOVE_BYTES_PER_LOOP_ITER / UNITS_PER_WORD ; unsigned iter_words = min_iter_words ; unsigned HOST_WIDE_INT bytes = hwi_length ; unsigned HOST_WIDE_INT words = bytes / UNITS_PER_WORD ; for ( unsigned i = min_iter_words ; i < min_iter_words * 2 - 1 ; i ++ ) { unsigned cur_cost = iter_words + words % iter_words ; unsigned new_cost = i + words % i ; if ( new_cost <= cur_cost ) iter_words = i ; } riscv_block_move_loop ( dest , src , bytes , iter_words * UNITS_PER_WORD ) ; return true ; } } return false ; } </s>

Expand a movmemsi instruction , which copies LENGTH bytes from memory reference SRC to memory reference DEST .


<s> void riscv_atomic_assign_expand_fenv ( tree * hold , tree * clear , tree * update ) { if ( ! ( TARGET_HARD_FLOAT || TARGET_ZFINX ) ) return ; tree frflags = GET_BUILTIN_DECL ( CODE_FOR_riscv_frflags ) ; tree fsflags = GET_BUILTIN_DECL ( CODE_FOR_riscv_fsflags ) ; tree old_flags = create_tmp_var_raw ( RISCV_ATYPE_USI ) ; * hold = build4 ( TARGET_EXPR , RISCV_ATYPE_USI , old_flags , build_call_expr ( frflags , 0 ) , NULL_TREE , NULL_TREE ) ; * clear = build_call_expr ( fsflags , 1 , old_flags ) ; * update = NULL_TREE ; } </s>


<s> unsigned RISCVTargetLowering :: getExceptionPointerRegister ( const Constant * PersonalityFn ) const { return RISCV :: X10 ; } </s>

If a physical register , this returns the register that receives the exception address on entry to an EH pad .


<s> void build ( function_builder & b , const function_group_info & group ) const override { auto_vec < tree > argument_types ; function_instance function_instance ( group . base_name , * group . base , * group . shape , group . ops_infos . types [ 0 ] , group . preds [ 0 ] , & group . ops_infos ) ; b . add_unique_function ( function_instance , ( * group . shape ) , long_unsigned_type_node , argument_types ) ; } </s>

Build new chain starting from insn INSN_UID recursively adding all dependent uses and definitions . Return true if OK , false if the chain discovery was aborted .


<s> OperandMatchResultTy RISCVAsmParser :: tryParseRegister ( unsigned & RegNo , SMLoc & StartLoc , SMLoc & EndLoc ) { const AsmToken & Tok = getParser ( ) . getTok ( ) ; StartLoc = Tok . getLoc ( ) ; EndLoc = Tok . getEndLoc ( ) ; RegNo = 0 ; StringRef Name = getLexer ( ) . getTok ( ) . getIdentifier ( ) ; if ( matchRegisterNameHelper ( isRV32E ( ) , ( Register & ) RegNo , Name ) ) return MatchOperand_NoMatch ; getParser ( ) . Lex ( ) ; return MatchOperand_Success ; } </s>

tryParseRegister - parse one register if possible


<s> unsigned RISCVTargetLowering :: getExceptionSelectorRegister ( const Constant * PersonalityFn ) const { if ( Subtarget . isRV64 ( ) ) return RISCV :: evec_64 ; else return RISCV :: evec ; } </s>

If a physical register , this returns the register that receives the exception typeid on entry to a landing pad .


<s>
static
void
riscv_file_start
(
void
)
{
default_file_start
(
)
;
fprintf
(
asm_out_file
,
"\t.option %spic\n"
,
(
flag_pic
""
:
"no"
)
)
;
if
(
!
riscv_mrelax
)
fprintf
(
asm_out_file
,
"\t.option norelax\n"
)
;
if
(
riscv_emit_attribute_p
)
riscv_emit_attribute
(
)
;
}
</s>

riscv
"\t.option %spic\n"
""
"no"
"\t.option norelax\n"


<s> Value * RISCVTargetLowering :: emitMaskedAtomicCmpXchgIntrinsic ( IRBuilder < > & Builder , AtomicCmpXchgInst * CI , Value * AlignedAddr , Value * CmpVal , Value * NewVal , Value * Mask , AtomicOrdering Ord ) const { unsigned XLen = Subtarget . getXLen ( ) ; Value * Ordering = Builder . getIntN ( XLen , static_cast < uint64_t > ( Ord ) ) ; Intrinsic :: ID CmpXchgIntrID = Intrinsic :: riscv_masked_cmpxchg_i32 ; if ( XLen == 64 ) { CmpVal = Builder . CreateSExt ( CmpVal , Builder . getInt64Ty ( ) ) ; NewVal = Builder . CreateSExt ( NewVal , Builder . getInt64Ty ( ) ) ; Mask = Builder . CreateSExt ( Mask , Builder . getInt64Ty ( ) ) ; CmpXchgIntrID = Intrinsic :: riscv_masked_cmpxchg_i64 ; } Type * Tys [ ] = { AlignedAddr -> getType ( ) } ; Function * MaskedCmpXchg = Intrinsic :: getDeclaration ( CI -> getModule ( ) , CmpXchgIntrID , Tys ) ; Value * Result = Builder . CreateCall ( MaskedCmpXchg , { AlignedAddr , CmpVal , NewVal , Mask , Ordering } ) ; if ( XLen == 64 ) Result = Builder . CreateTrunc ( Result , Builder . getInt32Ty ( ) ) ; return Result ; } </s>

Perform a masked cmpxchg using a target-specific intrinsic .


<s> void RISCVInstPrinter :: printInst ( const MCInst * MI , uint64_t Address , StringRef Annot , const MCSubtargetInfo & STI , raw_ostream & O ) { bool Res = false ; const MCInst * NewMI = MI ; MCInst UncompressedMI ; if ( PrintAliases && ! NoAliases ) Res = uncompressInst ( UncompressedMI , * MI , MRI , STI ) ; if ( Res ) NewMI = const_cast < MCInst * > ( & UncompressedMI ) ; if ( ! PrintAliases || NoAliases || ! printAliasInstr ( NewMI , Address , STI , O ) ) printInstruction ( NewMI , Address , STI , O ) ; printAnnotation ( O , Annot ) ; } </s>

Print the specified MCInst to the specified raw_ostream .


"There are no defined alternate asm variants"

PrintAsmOperand - Print out an operand for an inline asm expression .


<s> bool RISCVInstrInfo :: isAsCheapAsAMove ( const MachineInstr & MI ) const { const unsigned Opcode = MI . getOpcode ( ) ; switch ( Opcode ) { default : break ; case RISCV :: FSGNJ_D : case RISCV :: FSGNJ_S : return MI . getOperand ( 1 ) . isReg ( ) && MI . getOperand ( 2 ) . isReg ( ) && MI . getOperand ( 1 ) . getReg ( ) == MI . getOperand ( 2 ) . getReg ( ) ; case RISCV :: ADDI : case RISCV :: ORI : case RISCV :: XORI : return ( MI . getOperand ( 1 ) . isReg ( ) && MI . getOperand ( 1 ) . getReg ( ) == RISCV :: X0 ) || ( MI . getOperand ( 2 ) . isImm ( ) && MI . getOperand ( 2 ) . getImm ( ) == 0 ) ; } return MI . isAsCheapAsAMove ( ) ; } </s>

Return true if the instruction is as cheap as a move instruction .


<s> static bool riscv_cannot_force_const_mem ( enum machine_mode mode ATTRIBUTE_UNUSED , rtx x ) { enum riscv_symbol_type type ; rtx base , offset ; if ( GET_CODE ( x ) == HIGH ) return true ; split_const ( x , & base , & offset ) ; if ( riscv_symbolic_constant_p ( base , & type ) ) { if ( SMALL_OPERAND ( INTVAL ( offset ) ) && riscv_symbol_insns ( type ) > 0 ) return true ; if ( flag_pic ) return true ; } if ( tls_referenced_p ( x ) ) return true ; return false ; } </s>


<s> static void riscv_legitimize_const_move ( machine_mode mode , rtx dest , rtx src ) { rtx base , offset ; if ( splittable_const_int_operand ( src , mode ) ) { riscv_move_integer ( dest , dest , INTVAL ( src ) ) ; return ; } if ( riscv_split_symbol ( dest , src , MAX_MACHINE_MODE , & src ) ) { riscv_emit_set ( dest , src ) ; return ; } if ( riscv_tls_symbol_p ( src ) ) { riscv_emit_move ( dest , riscv_legitimize_tls_address ( src ) ) ; return ; } split_const ( src , & base , & offset ) ; if ( offset != const0_rtx && ( targetm . cannot_force_const_mem ( mode , src ) || can_create_pseudo_p ( ) ) ) { base = riscv_force_temporary ( dest , base ) ; riscv_emit_move ( dest , riscv_add_offset ( NULL , base , INTVAL ( offset ) ) ) ; return ; } src = force_const_mem ( mode , src ) ; riscv_split_symbol ( dest , XEXP ( src , 0 ) , mode , & XEXP ( src , 0 ) ) ; riscv_emit_move ( dest , src ) ; } </s>

Subroutine of riscv_legitimize_move . Move constant SRC into register DEST given that SRC satisfies immediate_operand but does n't satisfy move_operand .


<s> void riscv_move_integer ( rtx temp , rtx dest , HOST_WIDE_INT value ) { struct riscv_integer_op codes [ RISCV_MAX_INTEGER_OPS ] ; enum machine_mode mode ; int i , num_ops ; rtx x ; mode = GET_MODE ( dest ) ; num_ops = riscv_build_integer ( codes , value , mode ) ; if ( can_create_pseudo_p ( ) && num_ops > 2 && num_ops >= riscv_split_integer_cost ( value ) ) x = riscv_split_integer ( value , mode ) ; else { x = GEN_INT ( codes [ 0 ] . value ) ; for ( i = 1 ; i < num_ops ; i ++ ) { if ( ! can_create_pseudo_p ( ) ) x = riscv_emit_set ( temp , x ) ; else x = force_reg ( mode , x ) ; x = gen_rtx_fmt_ee ( codes [ i ] . code , mode , x , GEN_INT ( codes [ i ] . value ) ) ; } } riscv_emit_set ( dest , x ) ; } </s>

Load VALUE into DEST . TEMP is as for riscv_force_temporary .


<s> const RISCVSubtarget * getSubtargetImpl ( const Function & ) const override { return & Subtarget ; } </s>

Virtual method implemented by subclasses that returns a reference to that target 's TargetSubtargetInfo-derived member variable .


"RegScavenger required for long branching"

"new block should be inserted for expanding unconditional branch"

"Branch offsets outside of the signed 32-bit range not supported"

Insert an unconditional indirect branch at the end of MBB to NewDestBB .


<s> bool riscv_gpr_save_operation_p ( rtx op ) { unsigned len = XVECLEN ( op , 0 ) ; if ( len > ARRAY_SIZE ( gpr_save_reg_order ) ) return false ; for ( unsigned i = 0 ; i < len ; i ++ ) { rtx elt = XVECEXP ( op , 0 , i ) ; if ( i == 0 ) { if ( GET_CODE ( elt ) != UNSPEC_VOLATILE || GET_CODE ( XVECEXP ( elt , 0 , 0 ) ) != CONST_INT || XINT ( elt , 1 ) != UNSPECV_GPR_SAVE ) return false ; } else { unsigned expect_code = i < 3 ? CLOBBER : USE ; if ( GET_CODE ( elt ) != expect_code || ! REG_P ( XEXP ( elt , 1 ) ) || ( REGNO ( XEXP ( elt , 1 ) ) != gpr_save_reg_order [ i ] ) ) return false ; } break ; } return true ; } </s>

Return true if it 's valid gpr_save pattern .


"Frame offsets outside of the signed 32-bit range not supported"

This method must be overriden to eliminate abstract frame indices from instructions which may use them .


<s>
bool
RISCVInstrInfo
::
reverseBranchCondition
(
SmallVectorImpl
<
MachineOperand
>
&
Cond
)
const
{
if
(
Cond
[
0
]
.
getImm
(
)
==
RISCV
::
HwlpBranch
)
{
return
true
;
}
assert
(
(
Cond
.
size
(
)
==
3
)
&&
"Invalid branch condition!"
)
;
Cond
[
0
]
.
setImm
(
getOppositeBranchOpcode
(
Cond
[
0
]
.
getImm
(
)
)
)
;
return
false
;
}
</s>

Reverses the branch condition of the specified condition list , returning false on success and true if it can not be reversed .


<s> static bool riscv_classify_address ( struct riscv_address_info * info , rtx x , machine_mode mode , bool strict_p ) { switch ( GET_CODE ( x ) ) { case REG : case SUBREG : info -> type = ADDRESS_REG ; info -> reg = x ; info -> offset = const0_rtx ; return riscv_valid_base_register_p ( info -> reg , mode , strict_p ) ; case PLUS : if ( riscv_v_ext_vector_mode_p ( mode ) ) return false ; info -> type = ADDRESS_REG ; info -> reg = XEXP ( x , 0 ) ; info -> offset = XEXP ( x , 1 ) ; return ( riscv_valid_base_register_p ( info -> reg , mode , strict_p ) && riscv_valid_offset_p ( info -> offset , mode ) ) ; case LO_SUM : if ( riscv_v_ext_vector_mode_p ( mode ) ) return false ; info -> type = ADDRESS_LO_SUM ; info -> reg = XEXP ( x , 0 ) ; info -> offset = XEXP ( x , 1 ) ; info -> symbol_type = riscv_classify_symbolic_expression ( info -> offset ) ; return ( riscv_valid_base_register_p ( info -> reg , mode , strict_p ) && riscv_valid_lo_sum_p ( info -> symbol_type , mode , info -> offset ) ) ; case CONST_INT : if ( riscv_v_ext_vector_mode_p ( mode ) ) return false ; info -> type = ADDRESS_CONST_INT ; return SMALL_OPERAND ( INTVAL ( x ) ) ; default : return false ; } } </s>

Return true if X is a valid address for machine mode MODE . If it is , fill in INFO appropriately . STRICT_P is true if REG_OK_STRICT is in effect .


"insertBranch must not be told to insert a fallthrough"

"RISCV branch conditions have two components!"

Insert branch code into the end of the specified MachineBasicBlock .


<s> static void riscv_block_move_loop ( rtx dest , rtx src , unsigned HOST_WIDE_INT length , unsigned HOST_WIDE_INT bytes_per_iter ) { rtx label , src_reg , dest_reg , final_src , test ; unsigned HOST_WIDE_INT leftover ; leftover = length % bytes_per_iter ; length -= leftover ; riscv_adjust_block_mem ( src , bytes_per_iter , & src_reg , & src ) ; riscv_adjust_block_mem ( dest , bytes_per_iter , & dest_reg , & dest ) ; final_src = expand_simple_binop ( Pmode , PLUS , src_reg , GEN_INT ( length ) , 0 , 0 , OPTAB_WIDEN ) ; label = gen_label_rtx ( ) ; emit_label ( label ) ; riscv_block_move_straight ( dest , src , bytes_per_iter ) ; riscv_emit_move ( src_reg , plus_constant ( Pmode , src_reg , bytes_per_iter ) ) ; riscv_emit_move ( dest_reg , plus_constant ( Pmode , dest_reg , bytes_per_iter ) ) ; test = gen_rtx_NE ( VOIDmode , src_reg , final_src ) ; emit_jump_insn ( gen_cbranch4 ( Pmode , test , src_reg , final_src , label ) ) ; if ( leftover ) riscv_block_move_straight ( dest , src , leftover ) ; else emit_insn ( gen_nop ( ) ) ; } </s>

Move LENGTH bytes from SRC to DEST using a loop that moves BYTES_PER_ITER bytes at a time . LENGTH must be at least BYTES_PER_ITER . Assume that the memory regions do not overlap .


<s> bool const_vec_all_same_in_range_p ( rtx x , HOST_WIDE_INT minval , HOST_WIDE_INT maxval ) { rtx elt ; return ( const_vec_duplicate_p ( x , & elt ) && CONST_INT_P ( elt ) && IN_RANGE ( INTVAL ( elt ) , minval , maxval ) ) ; } </s>

Return true if X is a const_vector with all duplicate elements , which is in the range between MINVAL and MAXVAL .


<s>
const
MCPhysReg
*
RISCVRegisterInfo
::
getCalleeSavedRegs
(
const
MachineFunction
*
MF
)
const
{
auto
&
Subtarget
=
MF
->
getSubtarget
<
RISCVSubtarget
>
(
)
;
if
(
MF
->
getFunction
(
)
.
hasFnAttribute
(
"interrupt"
)
)
{
if
(
Subtarget
.
hasStdExtD
(
)
)
return
CSR_XLEN_F64_Interrupt_SaveList
;
if
(
Subtarget
.
hasStdExtF
(
)
)
return
CSR_XLEN_F32_Interrupt_SaveList
;
return
CSR_Interrupt_SaveList
;
}
switch
(
Subtarget
.
getTargetABI
(
)
)
{
default
:
llvm_unreachable
(
"Unrecognized ABI"
)
;
case
RISCVABI
::
ABI_ILP32
:
case
RISCVABI
::
ABI_LP64
:
return
CSR_ILP32_LP64_SaveList
;
case
RISCVABI
::
ABI_ILP32F
:
case
RISCVABI
::
ABI_LP64F
:
return
CSR_ILP32F_LP64F_SaveList
;
case
RISCVABI
::
ABI_ILP32D
:
case
RISCVABI
::
ABI_LP64D
:
return
CSR_ILP32D_LP64D_SaveList
;
}
}
</s>


"Can't store this register to stack slot"

Store the specified register of the given register class to the specified stack frame index .


<s> bool RISCVTargetLowering :: hasAndNotCompare ( SDValue Y ) const { EVT VT = Y . getValueType ( ) ; if ( VT . isVector ( ) ) return false ; return Subtarget . hasStdExtZbb ( ) && ! isa < ConstantSDNode > ( Y ) ; } </s>

Return true if the target should transform : ( X & Y ) == Y � ? ( ~X & Y ) == 0 ( X & Y ) ! = Y � ? ( ~X & Y ) ! = 0 .


<s> int get_ma ( rtx ma ) { if ( INTVAL ( ma ) == MASK_ANY ) return INVALID_ATTRIBUTE ; return INTVAL ( ma ) ; } </s>

Get ma according to operand [ mask_op_idx ] .


<s> static bool riscv_can_eliminate ( const int from ATTRIBUTE_UNUSED , const int to ) { return ( to == HARD_FRAME_POINTER_REGNUM || to == STACK_POINTER_REGNUM ) ; } </s>

Make sure that we 're not trying to eliminate to the wrong hard frame pointer .


<s> bool RISCVTTIImpl :: isHardwareLoopProfitable ( Loop * L , ScalarEvolution & SE , AssumptionCache & AC , TargetLibraryInfo * LibInfo , HardwareLoopInfo & HWLoopInfo ) { if ( ! ST -> hasNonStdExtPulp ( ) ) { return false ; } if ( ! SE . hasLoopInvariantBackedgeTakenCount ( L ) ) { return false ; } const SCEV * BackedgeTakenCount = SE . getBackedgeTakenCount ( L ) ; if ( isa < SCEVCouldNotCompute > ( BackedgeTakenCount ) ) { return false ; } const SCEV * TripCountSCEV = SE . getAddExpr ( BackedgeTakenCount , SE . getOne ( BackedgeTakenCount -> getType ( ) ) ) ; if ( SE . getUnsignedRangeMax ( TripCountSCEV ) . getBitWidth ( ) > 32 ) { return false ; } auto MaybeCall = [ this ] ( Instruction & I ) { const RISCVTargetLowering * TLI = getTLI ( ) ; unsigned ISD = TLI -> InstructionOpcodeToISD ( I . getOpcode ( ) ) ; EVT VT = TLI -> getValueType ( DL , I . getType ( ) , true ) ; if ( TLI -> getOperationAction ( ISD , VT ) == TargetLowering :: LibCall ) return true ; if ( auto * Call = dyn_cast < CallInst > ( & I ) ) { if ( isa < IntrinsicInst > ( Call ) ) { if ( const Function * F = Call -> getCalledFunction ( ) ) return isLoweredToCall ( F ) ; } return true ; } if ( VT . isFloatingPoint ( ) && ! TLI -> isOperationLegalOrCustom ( ISD , VT ) ) return true ; return false ; } ; auto IsHardwareLoopIntrinsic = [ ] ( Instruction & I ) { if ( auto * Call = dyn_cast < IntrinsicInst > ( & I ) ) { switch ( Call -> getIntrinsicID ( ) ) { default : break ; case Intrinsic :: set_loop_iterations : case Intrinsic :: test_set_loop_iterations : case Intrinsic :: loop_decrement : case Intrinsic :: loop_decrement_reg : return true ; } } return false ; } ; bool hasInnerHardwareLoop = false ; auto ScanLoop = [ & ] ( Loop * L ) { for ( auto * BB : L -> getBlocks ( ) ) { for ( auto & I : BB -> instructionsWithoutDebug ( ) ) { hasInnerHardwareLoop |= IsHardwareLoopIntrinsic ( I ) ; if ( MaybeCall ( I ) ) { return false ; } } } return true ; } ; for ( auto Inner : * L ) if ( ! ScanLoop ( Inner ) ) return false ; if ( ! ScanLoop ( L ) ) return false ; LLVMContext & C = L -> getHeader ( ) -> getContext ( ) ; HWLoopInfo . CounterInReg = false ; HWLoopInfo . IsNestingLegal = ! hasInnerHardwareLoop ; HWLoopInfo . PerformEntryTest = false ; HWLoopInfo . CountType = Type :: getInt32Ty ( C ) ; HWLoopInfo . LoopDecrement = ConstantInt :: get ( HWLoopInfo . CountType , 1 ) ; return true ; } </s>

Query the target whether it would be profitable to convert the given loop into a hardware loop .


<s> static void split_plus ( rtx x , rtx * base_ptr , HOST_WIDE_INT * offset_ptr ) { if ( GET_CODE ( x ) == PLUS && CONST_INT_P ( XEXP ( x , 1 ) ) ) { * base_ptr = XEXP ( x , 0 ) ; * offset_ptr = INTVAL ( XEXP ( x , 1 ) ) ; } else { * base_ptr = x ; * offset_ptr = 0 ; } } </s>

If X is a PLUS of a CONST_INT , return the two terms in * BASE_PTR and * OFFSET_PTR . Return X in * BASE_PTR and 0 in * OFFSET_PTR otherwise .


<s> bool RISCVFrameLowering :: hasReservedCallFrame ( const MachineFunction & MF ) const { return ! MF . getFrameInfo ( ) . hasVarSizedObjects ( ) ; } </s>

hasReservedCallFrame - Under normal circumstances , when a frame pointer is not required , we reserve argument space for call sites in the function immediately on entry to the current function .


<s> bool RISCVAsmPrinter :: runOnMachineFunction ( MachineFunction & MF ) { Subtarget = & MF . getSubtarget < RISCVSubtarget > ( ) ; return AsmPrinter :: runOnMachineFunction ( MF ) ; } </s>

runOnMachineFunction - Emit the function body .


<s> void RISCVPassConfig :: addIRPasses ( ) { addPass ( createAtomicExpandPass ( ) ) ; if ( TM -> getOptLevel ( ) == CodeGenOpt :: Aggressive && EnableGEPOpt ) { addPass ( createSeparateConstOffsetFromGEPPass ( true ) ) ; addPass ( createEarlyCSEPass ( ) ) ; addPass ( createLICMPass ( ) ) ; } TargetPassConfig :: addIRPasses ( ) ; } </s>

Add common target configurable passes that perform LLVM IR to IR transforms following machine independent optimization .


<s> uint8_t get_sew ( ) const { return m_sew ; } </s>

Helper function to get SEW operand . We always have SEW value for all RVV instructions that have VTYPE OP .


<s> static bool riscv_pass_by_reference ( cumulative_args_t cum_v , const function_arg_info & arg ) { HOST_WIDE_INT size = arg . type_size_in_bytes ( ) . to_constant ( ) ; ; struct riscv_arg_info info ; CUMULATIVE_ARGS * cum = get_cumulative_args ( cum_v ) ; if ( cum != NULL ) { riscv_get_arg_info ( & info , cum , arg . mode , arg . type , arg . named , false ) ; if ( info . num_fprs ) return false ; } return ! IN_RANGE ( size , 0 , 2 * UNITS_PER_WORD ) ; } </s>


<s> RISCVConstantPoolValue * RISCVConstantPoolValue :: Create ( const GlobalValue * GV , RISCVCP :: RISCVCPModifier Modifier ) { return new RISCVConstantPoolValue ( GV , Modifier ) ; } </s>

Construct a unary instruction , given the opcode and an operand .

RISCV RISCV RISCV RISCVCP::RISCVCPModifier RISCV


<s>
void
RISCVAsmBackend
::
applyFixup
(
const
MCAssembler
&
Asm
,
const
MCFixup
&
Fixup
,
const
MCValue
&
Target
,
MutableArrayRef
<
char
>
Data
,
uint64_t
Value
,
bool
IsResolved
)
const
{
MCContext
&
Ctx
=
Asm
.
getContext
(
)
;
MCFixupKindInfo
Info
=
getFixupKindInfo
(
Fixup
.
getKind
(
)
)
;
if
(
!
Value
)
return
;
Value
=
adjustFixupValue
(
Fixup
,
Value
,
Ctx
)
;
Value
<<=
Info
.
TargetOffset
;
unsigned
Offset
=
Fixup
.
getOffset
(
)
;
unsigned
NumBytes
=
(
Info
.
TargetSize
+
7
)
/
8
;
assert
(
Offset
+
NumBytes
<=
Data
.
size
(
)
&&
"Invalid fixup offset!"
)
;
for
(
unsigned
i
=
0
;
i
!=
4
;
++
i
)
{
Data
[
Offset
+
i
]
|=
uint8_t
(
(
Value
>>
(
i
*
8
)
)
&
0xff
)
;
}
}
</s>

Apply the Value for given Fixup into the provided data fragment , at the offset specified by the fixup and following the fixup kind as appropriate .


<s> void RISCVTargetStreamer :: emitTargetAttributes ( const MCSubtargetInfo & STI ) { if ( STI . hasFeature ( RISCV :: FeatureRV32E ) ) emitAttribute ( RISCVAttrs :: STACK_ALIGN , RISCVAttrs :: ALIGN_4 ) ; else emitAttribute ( RISCVAttrs :: STACK_ALIGN , RISCVAttrs :: ALIGN_16 ) ; std :: string Arch = "rv32" ; if ( STI . hasFeature ( RISCV :: Feature64Bit ) ) Arch = "rv64" ; if ( STI . hasFeature ( RISCV :: FeatureRV32E ) ) Arch += "e1p9" ; else Arch += "i2p0" ; if ( STI . hasFeature ( RISCV :: FeatureStdExtM ) ) Arch += "_m2p0" ; if ( STI . hasFeature ( RISCV :: FeatureStdExtA ) ) Arch += "_a2p0" ; if ( STI . hasFeature ( RISCV :: FeatureStdExtF ) ) Arch += "_f2p0" ; if ( STI . hasFeature ( RISCV :: FeatureStdExtD ) ) Arch += "_d2p0" ; if ( STI . hasFeature ( RISCV :: FeatureStdExtC ) ) Arch += "_c2p0" ; if ( STI . hasFeature ( RISCV :: FeatureStdExtB ) ) Arch += "_b0p93" ; if ( STI . hasFeature ( RISCV :: FeatureStdExtV ) ) Arch += "_v0p10" ; if ( STI . hasFeature ( RISCV :: FeatureExtZfh ) ) Arch += "_zfh0p1" ; if ( STI . hasFeature ( RISCV :: FeatureExtZba ) ) Arch += "_zba0p93" ; if ( STI . hasFeature ( RISCV :: FeatureExtZbb ) ) Arch += "_zbb0p93" ; if ( STI . hasFeature ( RISCV :: FeatureExtZbc ) ) Arch += "_zbc0p93" ; if ( STI . hasFeature ( RISCV :: FeatureExtZbe ) ) Arch += "_zbe0p93" ; if ( STI . hasFeature ( RISCV :: FeatureExtZbf ) ) Arch += "_zbf0p93" ; if ( STI . hasFeature ( RISCV :: FeatureExtZbm ) ) Arch += "_zbm0p93" ; if ( STI . hasFeature ( RISCV :: FeatureExtZbp ) ) Arch += "_zbp0p93" ; if ( STI . hasFeature ( RISCV :: FeatureExtZbproposedc ) ) Arch += "_zbproposedc0p93" ; if ( STI . hasFeature ( RISCV :: FeatureExtZbr ) ) Arch += "_zbr0p93" ; if ( STI . hasFeature ( RISCV :: FeatureExtZbs ) ) Arch += "_zbs0p93" ; if ( STI . hasFeature ( RISCV :: FeatureExtZbt ) ) Arch += "_zbt0p93" ; if ( STI . hasFeature ( RISCV :: FeatureExtZvamo ) ) Arch += "_zvamo0p10" ; if ( STI . hasFeature ( RISCV :: FeatureStdExtZvlsseg ) ) Arch += "_zvlsseg0p10" ; if ( STI . hasFeature ( RISCV :: FeatureCheri ) ) Arch += "_xcheri0p0" ; emitTextAttribute ( RISCVAttrs :: ARCH , Arch ) ; } </s>

Emit the build attributes that only depend on the hardware that we expect .


<s> inline bool function_base :: has_merge_operand_p ( ) const { return true ; } </s>

We choose to return true by default since most of the intrinsics use has merge operand .


<s>
MachineInstr
*
RISCVInstrInfo
::
convertToThreeAddress
(
MachineInstr
&
MI
,
LiveVariables
*
LV
,
LiveIntervals
*
LIS
)
const
{
switch
(
MI
.
getOpcode
(
)
)
{
default
:
break
;
case
CASE_WIDEOP_OPCODE_LMULS
(
FWADD_WV
)
:
case
CASE_WIDEOP_OPCODE_LMULS
(
FWSUB_WV
)
:
case
CASE_WIDEOP_OPCODE_LMULS
(
WADD_WV
)
:
case
CASE_WIDEOP_OPCODE_LMULS
(
WADDU_WV
)
:
case
CASE_WIDEOP_OPCODE_LMULS
(
WSUB_WV
)
:
case
CASE_WIDEOP_OPCODE_LMULS
(
WSUBU_WV
)
:
{
unsigned
NewOpc
;
switch
(
MI
.
getOpcode
(
)
)
{
default
:
llvm_unreachable
(
"Unexpected opcode"
)
;
CASE_WIDEOP_CHANGE_OPCODE_LMULS
(
FWADD_WV
)
CASE_WIDEOP_CHANGE_OPCODE_LMULS
(
FWSUB_WV
)
CASE_WIDEOP_CHANGE_OPCODE_LMULS
(
WADD_WV
)
CASE_WIDEOP_CHANGE_OPCODE_LMULS
(
WADDU_WV
)
CASE_WIDEOP_CHANGE_OPCODE_LMULS
(
WSUB_WV
)
CASE_WIDEOP_CHANGE_OPCODE_LMULS
(
WSUBU_WV
)
}
MachineBasicBlock
&
MBB
=
*
MI
.
getParent
(
)
;
MachineInstrBuilder
MIB
=
BuildMI
(
MBB
,
MI
,
MI
.
getDebugLoc
(
)
,
get
(
NewOpc
)
)
.
add
(
MI
.
getOperand
(
0
)
)
.
add
(
MI
.
getOperand
(
1
)
)
.
add
(
MI
.
getOperand
(
2
)
)
.
add
(
MI
.
getOperand
(
3
)
)
.
add
(
MI
.
getOperand
(
4
)
)
;
MIB
.
copyImplicitOps
(
MI
)
;
if
(
LV
)
{
unsigned
NumOps
=
MI
.
getNumOperands
(
)
;
for
(
unsigned
I
=
1
;
I
<
NumOps
;
++
I
)
{
MachineOperand
&
Op
=
MI
.
getOperand
(
I
)
;
if
(
Op
.
isReg
(
)
&&
Op
.
isKill
(
)
)
LV
->
replaceKillInstruction
(
Op
.
getReg
(
)
,
MI
,
*
MIB
)
;
}
}
if
(
LIS
)
{
SlotIndex
Idx
=
LIS
->
ReplaceMachineInstrInMaps
(
MI
,
*
MIB
)
;
if
(
MI
.
getOperand
(
0
)
.
isEarlyClobber
(
)
)
{
LiveInterval
&
LI
=
LIS
->
getInterval
(
MI
.
getOperand
(
1
)
.
getReg
(
)
)
;
LiveRange
::
Segment
*
S
=
LI
.
getSegmentContaining
(
Idx
)
;
if
(
S
->
end
==
Idx
.
getRegSlot
(
true
)
)
S
->
end
=
Idx
.
getRegSlot
(
)
;
}
}
return
MIB
;
}
}
return
nullptr
;
}
</s>

convertToThreeAddress - This method must be implemented by targets that set the M_CONVERTIBLE_TO_3_ADDR flag .


<s> unsigned RISCVInstrInfo :: getInstSizeInBytes ( const MachineInstr & MI ) const { unsigned Opcode = MI . getOpcode ( ) ; switch ( Opcode ) { default : { if ( MI . getParent ( ) && MI . getParent ( ) -> getParent ( ) ) { const auto MF = MI . getMF ( ) ; const auto & TM = static_cast < const RISCVTargetMachine & > ( MF -> getTarget ( ) ) ; const MCRegisterInfo & MRI = * TM . getMCRegisterInfo ( ) ; const MCSubtargetInfo & STI = * TM . getMCSubtargetInfo ( ) ; const RISCVSubtarget & ST = MF -> getSubtarget < RISCVSubtarget > ( ) ; if ( isCompressibleInst ( MI , & ST , MRI , STI ) ) return 2 ; } return get ( Opcode ) . getSize ( ) ; } case TargetOpcode :: EH_LABEL : case TargetOpcode :: IMPLICIT_DEF : case TargetOpcode :: KILL : case TargetOpcode :: DBG_VALUE : return 0 ; case RISCV :: PseudoCALLReg : case RISCV :: PseudoCALL : case RISCV :: PseudoJump : case RISCV :: PseudoTAIL : case RISCV :: PseudoLLA : case RISCV :: PseudoLA : case RISCV :: PseudoLA_TLS_IE : case RISCV :: PseudoLA_TLS_GD : return 8 ; case RISCV :: PseudoAtomicLoadNand32 : case RISCV :: PseudoAtomicLoadNand64 : return 20 ; case RISCV :: PseudoMaskedAtomicSwap32 : case RISCV :: PseudoMaskedAtomicLoadAdd32 : case RISCV :: PseudoMaskedAtomicLoadSub32 : return 28 ; case RISCV :: PseudoMaskedAtomicLoadNand32 : return 32 ; case RISCV :: PseudoMaskedAtomicLoadMax32 : case RISCV :: PseudoMaskedAtomicLoadMin32 : return 44 ; case RISCV :: PseudoMaskedAtomicLoadUMax32 : case RISCV :: PseudoMaskedAtomicLoadUMin32 : return 36 ; case RISCV :: PseudoCmpXchg32 : case RISCV :: PseudoCmpXchg64 : return 16 ; case RISCV :: PseudoMaskedCmpXchg32 : return 32 ; case TargetOpcode :: INLINEASM : case TargetOpcode :: INLINEASM_BR : { const MachineFunction & MF = * MI . getParent ( ) -> getParent ( ) ; const auto & TM = static_cast < const RISCVTargetMachine & > ( MF . getTarget ( ) ) ; return getInlineAsmLength ( MI . getOperand ( 0 ) . getSymbolName ( ) , * TM . getMCAsmInfo ( ) ) ; } case RISCV :: PseudoVSPILL2_M1 : case RISCV :: PseudoVSPILL2_M2 : case RISCV :: PseudoVSPILL2_M4 : case RISCV :: PseudoVSPILL3_M1 : case RISCV :: PseudoVSPILL3_M2 : case RISCV :: PseudoVSPILL4_M1 : case RISCV :: PseudoVSPILL4_M2 : case RISCV :: PseudoVSPILL5_M1 : case RISCV :: PseudoVSPILL6_M1 : case RISCV :: PseudoVSPILL7_M1 : case RISCV :: PseudoVSPILL8_M1 : case RISCV :: PseudoVRELOAD2_M1 : case RISCV :: PseudoVRELOAD2_M2 : case RISCV :: PseudoVRELOAD2_M4 : case RISCV :: PseudoVRELOAD3_M1 : case RISCV :: PseudoVRELOAD3_M2 : case RISCV :: PseudoVRELOAD4_M1 : case RISCV :: PseudoVRELOAD4_M2 : case RISCV :: PseudoVRELOAD5_M1 : case RISCV :: PseudoVRELOAD6_M1 : case RISCV :: PseudoVRELOAD7_M1 : case RISCV :: PseudoVRELOAD8_M1 : { unsigned NF = isRVVSpillForZvlsseg ( Opcode ) -> first ; return 4 * ( 2 * NF - 1 ) ; } } } </s>

Returns the size in bytes of the specified MachineInstr , or ~0U when this function is not implemented by a target .


<s> const TargetRegisterClass * RISCVRegisterInfo :: getLargestLegalSuperClass ( const TargetRegisterClass * RC , const MachineFunction & ) const { if ( RC == & RISCV :: VMV0RegClass ) return & RISCV :: VRRegClass ; return RC ; } </s>

Returns the largest super class of RC that is legal to use in the current sub-target and has the same spill size .

RISCV RISCV RISCV::VMV0RegClass RISCV::VRRegClass


<s> bool RISCVRegisterInfo :: isConstantPhysReg ( MCRegister PhysReg ) const { return PhysReg == RISCV :: X0 || PhysReg == RISCV :: C0 ; } </s>

Returns true if PhysReg is unallocatable and constant throughout the function .


<s> static void riscv_function_arg_advance ( cumulative_args_t cum_v , machine_mode mode , const_tree type , bool named ) { CUMULATIVE_ARGS * cum = get_cumulative_args ( cum_v ) ; struct riscv_arg_info info ; riscv_get_arg_info ( & info , cum , mode , type , named , false ) ; cum -> num_fprs = info . fpr_offset + info . num_fprs ; cum -> num_gprs = info . gpr_offset + info . num_gprs ; } </s>


<s> bool RISCVTargetLowering :: isDesirableToCommuteWithShift ( const SDNode * N , CombineLevel Level ) const { SDValue N0 = N -> getOperand ( 0 ) ; EVT Ty = N0 . getValueType ( ) ; if ( Ty . isScalarInteger ( ) && ( N0 . getOpcode ( ) == ISD :: ADD || N0 . getOpcode ( ) == ISD :: OR ) ) { auto * C1 = dyn_cast < ConstantSDNode > ( N0 -> getOperand ( 1 ) ) ; auto * C2 = dyn_cast < ConstantSDNode > ( N -> getOperand ( 1 ) ) ; if ( C1 && C2 ) { APInt C1Int = C1 -> getAPIntValue ( ) ; APInt ShiftedC1Int = C1Int << C2 -> getAPIntValue ( ) ; if ( isLegalAddImmediate ( ShiftedC1Int . getSExtValue ( ) ) ) return true ; if ( isLegalAddImmediate ( C1Int . getSExtValue ( ) ) ) return false ; int C1Cost = RISCVMatInt :: getIntMatCost ( C1Int , Ty . getSizeInBits ( ) , Subtarget . is64Bit ( ) ) ; int ShiftedC1Cost = RISCVMatInt :: getIntMatCost ( ShiftedC1Int , Ty . getSizeInBits ( ) , Subtarget . is64Bit ( ) ) ; if ( C1Cost < ShiftedC1Cost ) return false ; } } return true ; } </s>

Return true if it is profitable to move this shift by a constant amount through its operand , adjusting any immediate operands as necessary to preserve semantics .

RISCV RISCV 0 ISD::ADD ISD::OR 1 1 RISCVMatInt::getIntMatCost RISCVMatInt::getIntMatCost


<s> inline bool function_base :: can_be_overloaded_p ( enum predication_type_index ) const { return true ; } </s>

Since most of intrinsics can be overloaded , we set it true by default .


<s>
TargetTransformInfo
::
PopcntSupportKind
RISCVTTIImpl
::
getPopcntSupport
(
unsigned
TyWidth
)
{
assert
(
isPowerOf2_32
(
TyWidth
)
&&
"Ty width must be power of 2"
)
;
return
ST
->
hasStdExtZbb
(
)
TTI
::
PSK_FastHardware
:
TTI
::
PSK_Software
;
}
</s>

Return hardware support for population count .

RISCV
RISCV
"Ty width must be power of 2"


<s> static struct machine_function * riscv_init_machine_status ( void ) { return ggc_cleared_alloc < machine_function > ( ) ; } </s>

Allocate a chunk of memory for per-function machine-dependent data .


<s> BitVector RISCVRegisterInfo :: getReservedRegs ( const MachineFunction & MF ) const { const RISCVFrameLowering * TFI = getFrameLowering ( MF ) ; BitVector Reserved ( getNumRegs ( ) ) ; for ( size_t Reg = 0 ; Reg < getNumRegs ( ) ; Reg ++ ) { if ( MF . getSubtarget < RISCVSubtarget > ( ) . isRegisterReservedByUser ( Reg ) ) markSuperRegs ( Reserved , Reg ) ; } markSuperRegs ( Reserved , RISCV :: X0 ) ; markSuperRegs ( Reserved , RISCV :: X2 ) ; markSuperRegs ( Reserved , RISCV :: X3 ) ; markSuperRegs ( Reserved , RISCV :: X4 ) ; if ( TFI -> hasFP ( MF ) ) markSuperRegs ( Reserved , RISCV :: X8 ) ; if ( TFI -> hasBP ( MF ) ) markSuperRegs ( Reserved , RISCVABI :: getBPReg ( ) ) ; markSuperRegs ( Reserved , RISCV :: VL ) ; markSuperRegs ( Reserved , RISCV :: VTYPE ) ; markSuperRegs ( Reserved , RISCV :: VXSAT ) ; markSuperRegs ( Reserved , RISCV :: VXRM ) ; assert ( checkAllSuperRegsMarked ( Reserved ) ) ; return Reserved ; } </s>

getReservedRegs - Returns a bitset indexed by physical register number indicating if a register is a special register that has particular uses and should be considered unavailable at all times , e.g .


<s> inline void function_expander :: add_fixed_operand ( rtx x ) { create_fixed_operand ( & m_ops [ opno ++ ] , x ) ; } </s>

Add an operand that must be X . The only way of legitimizing an invalid X is to reload the address of a MEM .


<s> void getAnalysisUsage ( AnalysisUsage & AU ) const override { AU . setPreservesCFG ( ) ; AU . addRequired < TargetPassConfig > ( ) ; AU . addRequired < LoopInfoWrapperPass > ( ) ; } </s>

getAnalysisUsage - Subclasses that override getAnalysisUsage must call this .


<s> const MCPhysReg * RISCVRegisterInfo :: getCalleeSavedRegs ( const MachineFunction * MF ) const { auto & Subtarget = MF -> getSubtarget < RISCVSubtarget > ( ) ; if ( MF -> getFunction ( ) . hasFnAttribute ( "interrupt" ) ) { if ( Subtarget . hasStdExtD ( ) ) return CSR_XLEN_F64_Interrupt_SaveList ; if ( Subtarget . hasStdExtF ( ) ) return CSR_XLEN_F32_Interrupt_SaveList ; return CSR_Interrupt_SaveList ; } return CSR_ILP32_LP64_SaveList ; } </s>


<s>
SDNode
*
RISCVDAGToDAGISel
::
Select
(
SDNode
*
Node
)
{
SDLoc
DL
(
Node
)
;
DEBUG
(
errs
(
)
<<
"Selecting: "
;
Node
->
dump
(
CurDAG
)
;
errs
(
)
<<
"\n"
)
;
if
(
Node
->
isMachineOpcode
(
)
)
{
DEBUG
(
errs
(
)
<<
"== "
;
Node
->
dump
(
CurDAG
)
;
errs
(
)
<<
"\n"
)
;
return
0
;
}
unsigned
Opcode
=
Node
->
getOpcode
(
)
;
switch
(
Opcode
)
{
case
ISD
::
FrameIndex
:
{
SDValue
imm
=
CurDAG
->
getTargetConstant
(
0
,
DL
,
Subtarget
.
isRV64
(
)
MVT
::
i64
:
MVT
::
i32
)
;
int
FI
=
cast
<
FrameIndexSDNode
>
(
Node
)
->
getIndex
(
)
;
SDValue
TFI
=
CurDAG
->
getTargetFrameIndex
(
FI
,
getTargetLowering
(
)
->
getPointerTy
(
CurDAG
->
getDataLayout
(
)
)
)
;
unsigned
Opc
=
Subtarget
.
isRV64
(
)
RISCV
::
ADDI64
:
RISCV
::
ADDI
;
EVT
VT
=
Subtarget
.
isRV64
(
)
MVT
::
i64
:
MVT
::
i32
;
if
(
Node
->
hasOneUse
(
)
)
return
CurDAG
->
SelectNodeTo
(
Node
,
Opc
,
VT
,
TFI
,
imm
)
;
return
CurDAG
->
getMachineNode
(
Opc
,
DL
,
VT
,
TFI
,
imm
)
;
}
}
SDNode
*
ResNode
=
SelectCode
(
Node
)
;
DEBUG
(
errs
(
)
<<
"=> "
;
if
(
ResNode
==
||
ResNode
==
Node
)
Node
->
dump
(
CurDAG
)
;
else
ResNode
->
dump
(
CurDAG
)
;
errs
(
)
<<
"\n"
;
)
;
return
ResNode
;
}
</s>

Main hook for targets to transform nodes into machine nodes .


<s> unsigned getNumFixupKinds ( ) const override { return RISCV :: NumTargetFixupKinds ; } </s>

Get the number of target specific fixup kinds .


<s> static bool tail_agnostic_p ( rtx_insn * rinsn ) { extract_insn_cached ( rinsn ) ; int ta = get_attr_ta ( rinsn ) ; return ta == INVALID_ATTRIBUTE ? get_default_ta ( ) : IS_AGNOSTIC ( ta ) ; } </s>


<s> InstructionCost RISCVTTIImpl :: getIntrinsicInstrCost ( const IntrinsicCostAttributes & ICA , TTI :: TargetCostKind CostKind ) { auto * RetTy = ICA . getReturnType ( ) ; switch ( ICA . getID ( ) ) { case Intrinsic :: experimental_stepvector : { unsigned Cost = 1 ; auto LT = TLI -> getTypeLegalizationCost ( DL , RetTy ) ; return Cost + ( LT . first - 1 ) ; } default : break ; } return BaseT :: getIntrinsicInstrCost ( ICA , CostKind ) ; } </s>


<s> bool function_checker :: require_immediate ( unsigned int argno , HOST_WIDE_INT min , HOST_WIDE_INT max ) const { gcc_assert ( argno < m_nargs ) ; tree arg = m_args [ argno ] ; if ( ! tree_fits_uhwi_p ( arg ) ) { report_non_ice ( argno ) ; return false ; } return require_immediate_range ( argno , min , max ) ; } </s>

Check that argument ARGNO is an integer constant expression and store its value in VALUE_OUT if so . The caller should first check that argument ARGNO exists .


<s> static enum flt_eval_method riscv_excess_precision ( enum excess_precision_type type ) { switch ( type ) { case EXCESS_PRECISION_TYPE_FAST : case EXCESS_PRECISION_TYPE_STANDARD : return ( ( TARGET_ZFH || TARGET_ZHINX ) ? FLT_EVAL_METHOD_PROMOTE_TO_FLOAT16 : FLT_EVAL_METHOD_PROMOTE_TO_FLOAT ) ; case EXCESS_PRECISION_TYPE_IMPLICIT : case EXCESS_PRECISION_TYPE_FLOAT16 : return FLT_EVAL_METHOD_PROMOTE_TO_FLOAT16 ; default : gcc_unreachable ( ) ; } return FLT_EVAL_METHOD_UNPREDICTABLE ; } </s>

Set the value of FLT_EVAL_METHOD . ISO/IEC TS 18661-3 defines two values that we 'd like to make use of : 0 : evaluate all operations and constants , whose semantic type has at most the range and precision of type float , to the range and precision of float ; evaluate all other operations and constants to the range and precision of the semantic type ; N , where _FloatN is a supported interchange floating type evaluate all operations and constants , whose semantic type has at most the range and precision of _FloatN type , to the range and precision of the _FloatN type ; evaluate all other operations and constants to the range and precision of the semantic type ; If we have the zfh/zhinx extensions then we support _Float16 in native precision , so we should set this to 16 .


<s> static rtx riscv_unspec_offset_high ( rtx temp , rtx addr , enum riscv_symbol_type symbol_type ) { addr = gen_rtx_HIGH ( Pmode , riscv_unspec_address ( addr , symbol_type ) ) ; return riscv_force_temporary ( temp , addr , FALSE ) ; } </s>

If riscv_unspec_address ( ADDR , SYMBOL_TYPE ) is a 32-bit value , add the high part to BASE and return the result . Just return BASE otherwise . TEMP is as for riscv_force_temporary . The returned expression can be used as the first operand to a LO_SUM .


<s> bool riscv_epilogue_uses ( unsigned int regno ) { if ( regno == RETURN_ADDR_REGNUM ) return true ; if ( epilogue_completed && cfun -> machine -> interrupt_handler_p ) { if ( df_regs_ever_live_p ( regno ) || ( ! crtl -> is_leaf && call_used_or_fixed_reg_p ( regno ) ) ) return true ; } return false ; } </s>


<s> bool RISCVMCExpr :: evaluateAsConstant ( int64_t & Res ) const { MCValue Value ; if ( Kind == VK_RISCV_PCREL_HI ) return false ; if ( ! getSubExpr ( ) -> evaluateAsRelocatable ( Value , nullptr , nullptr ) ) return false ; if ( ! Value . isAbsolute ( ) ) return false ; Res = evaluateAsInt64 ( Value . getConstant ( ) ) ; return true ; } </s>

Evaluates the fixup as a constant value .


<s> void RISCVInstrInfo :: loadRegFromStackSlot ( MachineBasicBlock & MBB , MachineBasicBlock :: iterator MBBI , unsigned DestReg , int FrameIdx , const TargetRegisterClass * RC , const TargetRegisterInfo * TRI ) const { DebugLoc DL = MBBI != MBB . end ( ) ? MBBI -> getDebugLoc ( ) : DebugLoc ( ) ; unsigned LoadOpcode , StoreOpcode ; getLoadStoreOpcodes ( RC , LoadOpcode , StoreOpcode ) ; addFrameReference ( BuildMI ( MBB , MBBI , DL , get ( LoadOpcode ) , DestReg ) , FrameIdx ) ; } </s>

Load the specified register of the given register class from the specified stack frame index .


<s>
void
RISCVDAGToDAGISel
::
PreprocessISelDAG
(
)
{
for
(
SelectionDAG
::
allnodes_iterator
I
=
CurDAG
->
allnodes_begin
(
)
,
E
=
CurDAG
->
allnodes_end
(
)
;
I
!=
E
;
)
{
SDNode
*
N
=
&
*
I
++
;
if
(
N
->
getOpcode
(
)
!=
RISCVISD
::
SPLAT_VECTOR_SPLIT_I64_VL
)
continue
;
assert
(
N
->
getNumOperands
(
)
==
3
&&
"Unexpected number of operands"
)
;
MVT
VT
=
N
->
getSimpleValueType
(
0
)
;
SDValue
Lo
=
N
->
getOperand
(
0
)
;
SDValue
Hi
=
N
->
getOperand
(
1
)
;
SDValue
VL
=
N
->
getOperand
(
2
)
;
assert
(
VT
.
getVectorElementType
(
)
==
MVT
::
i64
&&
VT
.
isScalableVector
(
)
&&
Lo
.
getValueType
(
)
==
MVT
::
i32
&&
Hi
.
getValueType
(
)
==
MVT
::
i32
&&
"Unexpected VTs!"
)
;
MachineFunction
&
MF
=
CurDAG
->
getMachineFunction
(
)
;
RISCVMachineFunctionInfo
*
FuncInfo
=
MF
.
getInfo
<
RISCVMachineFunctionInfo
>
(
)
;
SDLoc
DL
(
N
)
;
int
FI
=
FuncInfo
->
getMoveF64FrameIndex
(
MF
)
;
MachinePointerInfo
MPI
=
MachinePointerInfo
::
getFixedStack
(
MF
,
FI
)
;
const
TargetLowering
&
TLI
=
CurDAG
->
getTargetLoweringInfo
(
)
;
SDValue
StackSlot
=
CurDAG
->
getFrameIndex
(
FI
,
TLI
.
getPointerTy
(
CurDAG
->
getDataLayout
(
)
,
CurDAG
->
getDataLayout
(
)
.
getAllocaAddrSpace
(
)
)
)
;
SDValue
Chain
=
CurDAG
->
getEntryNode
(
)
;
Lo
=
CurDAG
->
getStore
(
Chain
,
DL
,
Lo
,
StackSlot
,
MPI
,
Align
(
8
)
)
;
SDValue
OffsetSlot
=
CurDAG
->
getMemBasePlusOffset
(
StackSlot
,
TypeSize
::
Fixed
(
4
)
,
DL
)
;
Hi
=
CurDAG
->
getStore
(
Chain
,
DL
,
Hi
,
OffsetSlot
,
MPI
.
getWithOffset
(
4
)
,
Align
(
8
)
)
;
Chain
=
CurDAG
->
getNode
(
ISD
::
TokenFactor
,
DL
,
MVT
::
Other
,
Lo
,
Hi
)
;
SDVTList
VTs
=
CurDAG
->
getVTList
(
{
VT
,
MVT
::
Other
}
)
;
SDValue
IntID
=
CurDAG
->
getTargetConstant
(
Intrinsic
::
riscv_vlse
,
DL
,
MVT
::
i64
)
;
SDValue
Ops
[
]
=
{
Chain
,
IntID
,
StackSlot
,
CurDAG
->
getRegister
(
RISCV
::
X0
,
MVT
::
i64
)
,
VL
}
;
SDValue
Result
=
CurDAG
->
getMemIntrinsicNode
(
ISD
::
INTRINSIC_W_CHAIN
,
DL
,
VTs
,
Ops
,
MVT
::
i64
,
MPI
,
Align
(
8
)
,
MachineMemOperand
::
MOLoad
)
;
I
;
CurDAG
->
ReplaceAllUsesOfValueWith
(
SDValue
(
N
,
0
)
,
Result
)
;
++
I
;
CurDAG
->
DeleteNode
(
N
)
;
}
}
</s>

PreprocessISelDAG - This hook allows targets to hack on the graph before instruction selection starts .


"Can only merge with a valid VSETVLInfo"


<s>
bool
RISCVInstrInfo
::
verifyInstruction
(
const
MachineInstr
&
MI
,
StringRef
&
ErrInfo
)
const
{
const
MCInstrInfo
*
MCII
=
STI
.
getInstrInfo
(
)
;
MCInstrDesc
const
&
Desc
=
MCII
->
get
(
MI
.
getOpcode
(
)
)
;
for
(
auto
&
OI
:
enumerate
(
Desc
.
operands
(
)
)
)
{
unsigned
OpType
=
OI
.
value
(
)
.
OperandType
;
if
(
OpType
>=
RISCVOp
::
OPERAND_FIRST_RISCV_IMM
&&
OpType
<=
RISCVOp
::
OPERAND_LAST_RISCV_IMM
)
{
const
MachineOperand
&
MO
=
MI
.
getOperand
(
OI
.
index
(
)
)
;
if
(
MO
.
isImm
(
)
)
{
int64_t
Imm
=
MO
.
getImm
(
)
;
bool
Ok
;
switch
(
OpType
)
{
default
:
llvm_unreachable
(
"Unexpected operand type"
)
;
case
RISCVOp
::
OPERAND_UIMM4
:
Ok
=
isUInt
<
4
>
(
Imm
)
;
break
;
case
RISCVOp
::
OPERAND_UIMM5
:
Ok
=
isUInt
<
5
>
(
Imm
)
;
break
;
case
RISCVOp
::
OPERAND_UIMM12
:
Ok
=
isUInt
<
12
>
(
Imm
)
;
break
;
case
RISCVOp
::
OPERAND_SIMM12
:
Ok
=
isInt
<
12
>
(
Imm
)
;
break
;
case
RISCVOp
::
OPERAND_SIMM13_LSB0
:
Ok
=
isShiftedInt
<
12
,
1
>
(
Imm
)
;
break
;
case
RISCVOp
::
OPERAND_UIMM20
:
Ok
=
isUInt
<
20
>
(
Imm
)
;
break
;
case
RISCVOp
::
OPERAND_SIMM21_LSB0
:
Ok
=
isShiftedInt
<
20
,
1
>
(
Imm
)
;
break
;
case
RISCVOp
::
OPERAND_UIMMLOG2XLEN
:
if
(
STI
.
getTargetTriple
(
)
.
isArch64Bit
(
)
)
Ok
=
isUInt
<
6
>
(
Imm
)
;
else
Ok
=
isUInt
<
5
>
(
Imm
)
;
break
;
}
if
(
!
Ok
)
{
ErrInfo
=
"Invalid immediate"
;
return
false
;
}
}
}
}
return
true
;
}
</s>

Perform target-specific instruction verification .


<s> unsigned RISCVInstrInfo :: isLoadFromStackSlot ( const MachineInstr & MI , int & FrameIndex ) const { return isSimpleMove ( MI , FrameIndex , RISCVII :: SimpleLoad ) ; } </s>

isLoadFromStackSlot - If the specified machine instruction is a direct load from a stack slot , return the virtual or physical register number of the destination along with the FrameIndex of the loaded stack slot .


<s> InstructionCost RISCVTTIImpl :: getMinMaxReductionCost ( VectorType * Ty , VectorType * CondTy , bool IsUnsigned , TTI :: TargetCostKind CostKind ) { if ( ! isa < FixedVectorType > ( Ty ) ) return BaseT :: getMinMaxReductionCost ( Ty , CondTy , IsUnsigned , CostKind ) ; if ( ! ST -> useRVVForFixedLengthVectors ( ) ) return BaseT :: getMinMaxReductionCost ( Ty , CondTy , IsUnsigned , CostKind ) ; if ( Ty -> getScalarSizeInBits ( ) > ST -> getMaxELENForFixedLengthVectors ( ) ) return BaseT :: getMinMaxReductionCost ( Ty , CondTy , IsUnsigned , CostKind ) ; InstructionCost BaseCost = 2 ; unsigned VL = cast < FixedVectorType > ( Ty ) -> getNumElements ( ) ; std :: pair < InstructionCost , MVT > LT = TLI -> getTypeLegalizationCost ( DL , Ty ) ; return ( LT . first - 1 ) + BaseCost + Log2_32_Ceil ( VL ) ; } </s>

Try to calculate op costs for min/max reduction operations .


<s> inline bool function_base :: apply_vl_p ( ) const { return true ; } </s>

We choose to apply vl operand by default since most of the intrinsics has vl operand .


<s> Instruction * RISCVTargetLowering :: emitLeadingFence ( IRBuilder < > & Builder , Instruction * Inst , AtomicOrdering Ord ) const { if ( isa < LoadInst > ( Inst ) && Ord == AtomicOrdering :: SequentiallyConsistent ) return Builder . CreateFence ( Ord ) ; if ( isa < StoreInst > ( Inst ) && isReleaseOrStronger ( Ord ) ) return Builder . CreateFence ( AtomicOrdering :: Release ) ; return nullptr ; } </s>


<s> unsigned RISCVTargetLowering :: getNumRegistersForCallingConv ( LLVMContext & Context , CallingConv :: ID CC , EVT VT ) const { if ( VT == MVT :: f16 && Subtarget . hasStdExtF ( ) && ! Subtarget . hasStdExtZfh ( ) ) return 1 ; return TargetLowering :: getNumRegistersForCallingConv ( Context , CC , VT ) ; } </s>

Certain targets require unusual breakdowns of certain types .


<s> bool RISCVTargetLowering :: signExtendConstant ( const ConstantInt * CI ) const { return Subtarget . is64Bit ( ) && CI -> getType ( ) -> isIntegerTy ( 32 ) ; } </s>

Return true if this constant should be sign extended when promoting to a larger type .


<s> bool RISCVTargetLowering :: shouldSinkOperands ( Instruction * I , SmallVectorImpl < Use * > & Ops ) const { using namespace llvm :: PatternMatch ; if ( ! I -> getType ( ) -> isVectorTy ( ) || ! Subtarget . hasVInstructions ( ) ) return false ; auto IsSinker = [ & ] ( Instruction * I , int Operand ) { switch ( I -> getOpcode ( ) ) { case Instruction :: Add : case Instruction :: Sub : case Instruction :: Mul : case Instruction :: And : case Instruction :: Or : case Instruction :: Xor : case Instruction :: FAdd : case Instruction :: FSub : case Instruction :: FMul : case Instruction :: FDiv : case Instruction :: ICmp : case Instruction :: FCmp : return true ; case Instruction :: Shl : case Instruction :: LShr : case Instruction :: AShr : return Operand == 1 ; case Instruction :: Call : if ( auto * II = dyn_cast < IntrinsicInst > ( I ) ) { switch ( II -> getIntrinsicID ( ) ) { case Intrinsic :: fma : return Operand == 0 || Operand == 1 ; default : return false ; } } return false ; default : return false ; } } ; for ( auto OpIdx : enumerate ( I -> operands ( ) ) ) { if ( ! IsSinker ( I , OpIdx . index ( ) ) ) continue ; Instruction * Op = dyn_cast < Instruction > ( OpIdx . value ( ) . get ( ) ) ; if ( ! Op || any_of ( Ops , [ & ] ( Use * U ) { return U -> get ( ) == Op ; } ) ) continue ; if ( ! match ( Op , m_Shuffle ( m_InsertElt ( m_Undef ( ) , m_Value ( ) , m_ZeroInt ( ) ) , m_Undef ( ) , m_ZeroMask ( ) ) ) ) continue ; for ( Use & U : Op -> uses ( ) ) { Instruction * Insn = cast < Instruction > ( U . getUser ( ) ) ; if ( ! IsSinker ( Insn , U . getOperandNo ( ) ) ) return false ; } Ops . push_back ( & Op -> getOperandUse ( 0 ) ) ; Ops . push_back ( & OpIdx . value ( ) ) ; } return true ; } </s>

Return true if sinking I 's operands to the same basic block as I is profitable , e.g .


<s> rtx function_expander :: use_ternop_insn ( bool vd_accum_p , insn_code icode ) { machine_mode mode = TYPE_MODE ( builtin_types [ type . index ] . vector ) ; int arg_offset = 0 ; if ( use_real_mask_p ( pred ) ) add_input_operand ( arg_offset ++ ) ; else add_all_one_mask_operand ( mask_mode ( ) ) ; rtx vd = expand_normal ( CALL_EXPR_ARG ( exp , arg_offset ++ ) ) ; rtx vs1 = expand_normal ( CALL_EXPR_ARG ( exp , arg_offset ++ ) ) ; rtx vs2 = expand_normal ( CALL_EXPR_ARG ( exp , arg_offset ++ ) ) ; if ( VECTOR_MODE_P ( GET_MODE ( vs1 ) ) ) { if ( ! vd_accum_p ) add_input_operand ( mode , vd ) ; add_input_operand ( mode , vs1 ) ; add_input_operand ( mode , vs2 ) ; if ( vd_accum_p ) add_input_operand ( mode , vd ) ; add_input_operand ( mode , vd ) ; } else { add_input_operand ( GET_MODE_INNER ( mode ) , vs1 ) ; if ( vd_accum_p ) { add_input_operand ( mode , vs2 ) ; add_input_operand ( mode , vd ) ; } else { add_input_operand ( mode , vd ) ; add_input_operand ( mode , vs2 ) ; } add_input_operand ( mode , vd ) ; } for ( int argno = arg_offset ; argno < call_expr_nargs ( exp ) ; argno ++ ) add_input_operand ( argno ) ; add_input_operand ( Pmode , get_tail_policy_for_pred ( pred ) ) ; add_input_operand ( Pmode , get_mask_policy_for_pred ( pred ) ) ; add_input_operand ( Pmode , get_avl_type_rtx ( avl_type :: NONVLMAX ) ) ; return generate_insn ( icode ) ; } </s>

Implement the call using instruction ICODE , with a 1:1 mapping between arguments and input operands .


<s> static void riscv_extend_comparands ( rtx_code code , rtx * op0 , rtx * op1 ) { if ( GET_MODE_SIZE ( word_mode ) > GET_MODE_SIZE ( GET_MODE ( * op0 ) ) ) { if ( unsigned_condition ( code ) == code && ( GET_MODE ( * op0 ) == QImode && ! ( GET_CODE ( * op0 ) == SUBREG && SUBREG_PROMOTED_VAR_P ( * op0 ) && SUBREG_PROMOTED_SIGNED_P ( * op0 ) && ( CONST_INT_P ( * op1 ) || ( GET_CODE ( * op1 ) == SUBREG && SUBREG_PROMOTED_VAR_P ( * op1 ) && SUBREG_PROMOTED_SIGNED_P ( * op1 ) ) ) ) ) ) { * op0 = gen_rtx_ZERO_EXTEND ( word_mode , * op0 ) ; if ( CONST_INT_P ( * op1 ) ) * op1 = GEN_INT ( ( uint8_t ) INTVAL ( * op1 ) ) ; else * op1 = gen_rtx_ZERO_EXTEND ( word_mode , * op1 ) ; } else { * op0 = gen_rtx_SIGN_EXTEND ( word_mode , * op0 ) ; if ( * op1 != const0_rtx ) * op1 = gen_rtx_SIGN_EXTEND ( word_mode , * op1 ) ; } } } </s>

Sign- or zero-extend OP0 and OP1 for integer comparisons .


<s> bool RISCVAsmParser :: ParseDirective ( AsmToken DirectiveID ) { StringRef IDVal = DirectiveID . getString ( ) ; if ( IDVal == ".option" ) return parseDirectiveOption ( ) ; else if ( IDVal == ".attribute" ) return parseDirectiveAttribute ( ) ; return true ; } </s>

ParseDirective - Parse a target specific assembler directive This method is deprecated , use 'parseDirective ' instead .


"ABI for flattened struct with zero-length "

See whether TYPE is a record whose fields should be returned in one or floating-point register and one integer register . If so , populate FIELDS accordingly .


<s> void RISCVDAGToDAGISel :: PostprocessISelDAG ( ) { HandleSDNode Dummy ( CurDAG -> getRoot ( ) ) ; SelectionDAG :: allnodes_iterator Position = CurDAG -> allnodes_end ( ) ; bool MadeChange = false ; while ( Position != CurDAG -> allnodes_begin ( ) ) { SDNode * N = & * -- Position ; if ( N -> use_empty ( ) || ! N -> isMachineOpcode ( ) ) continue ; MadeChange |= doPeepholeSExtW ( N ) ; MadeChange |= doPeepholeLoadStoreADDI ( N ) ; MadeChange |= doPeepholeMaskedRVV ( N ) ; } CurDAG -> setRoot ( Dummy . getValue ( ) ) ; if ( MadeChange ) CurDAG -> RemoveDeadNodes ( ) ; } </s>

PostprocessISelDAG ( ) - This hook allows the target to hack on the graph right after selection .


<s> int riscv_address_insns ( rtx x , machine_mode mode , bool might_split_p ) { struct riscv_address_info addr = { } ; int n = 1 ; if ( ! riscv_classify_address ( & addr , x , mode , false ) ) { return 3 ; } if ( mode != BLKmode && might_split_p ) n += ( GET_MODE_SIZE ( mode ) + UNITS_PER_WORD - 1 ) / UNITS_PER_WORD ; if ( addr . type == ADDRESS_LO_SUM ) n += riscv_symbol_insns ( addr . symbol_type ) - 1 ; return n ; } </s>

Return the number of instructions needed to load or store a value of mode MODE at address X . Return 0 if X is n't valid for MODE . Assume that multiword moves may need to be split into word moves if MIGHT_SPLIT_P , otherwise assume that a single load or store is enough .


"-mdiv requires -march to subsume the %<M%> extension"

"requested ABI requires -march to subsume the %qc extension"

"-mpreferred-stack-boundary=%d must be between %d and %d"


<s> static SDValue getTargetNode ( ExternalSymbolSDNode * N , SDLoc DL , EVT Ty , SelectionDAG & DAG , unsigned Flags ) { return DAG . getTargetExternalSymbol ( N -> getSymbol ( ) , Ty , Flags ) ; } </s>

Retrieve the target node this edge connects to .


<s> int RISCVFrameLowering :: getFrameIndexReference ( const MachineFunction & MF , int FI , Register & FrameReg ) const { const MachineFrameInfo & MFI = MF . getFrameInfo ( ) ; const TargetRegisterInfo * RI = MF . getSubtarget ( ) . getRegisterInfo ( ) ; const auto * RVFI = MF . getInfo < RISCVMachineFunctionInfo > ( ) ; bool HasRISCVVector = RVFI -> hasSpillVRs ( ) ; const auto & CSI = getNonLibcallCSI ( MFI . getCalleeSavedInfo ( ) ) ; int MinCSFI = 0 ; int MaxCSFI = - 1 ; int Offset = MFI . getObjectOffset ( FI ) - getOffsetOfLocalArea ( ) + MFI . getOffsetAdjustment ( ) ; uint64_t FirstSPAdjustAmount = getFirstSPAdjustAmount ( MF ) ; if ( CSI . size ( ) ) { MinCSFI = CSI [ 0 ] . getFrameIdx ( ) ; MaxCSFI = CSI [ CSI . size ( ) - 1 ] . getFrameIdx ( ) ; } if ( FI >= MinCSFI && FI <= MaxCSFI ) { FrameReg = RISCV :: X2 ; if ( FirstSPAdjustAmount ) Offset += FirstSPAdjustAmount ; else Offset += MFI . getStackSize ( ) ; } else if ( RI -> needsStackRealignment ( MF ) && ! MFI . isFixedObjectIndex ( FI ) ) { if ( hasBP ( MF ) ) FrameReg = RISCVABI :: getBPReg ( ) ; else FrameReg = RISCV :: X2 ; Offset += MFI . getStackSize ( ) ; if ( FI < 0 ) Offset += RVFI -> getLibCallStackSize ( ) ; } else { FrameReg = RI -> getFrameRegister ( MF ) ; if ( hasFP ( MF ) ) { Offset += RVFI -> getVarArgsSaveSize ( ) ; if ( FI >= 0 ) Offset -= RVFI -> getLibCallStackSize ( ) ; } else { Offset += MFI . getStackSize ( ) ; if ( FI < 0 ) Offset += RVFI -> getLibCallStackSize ( ) ; } } return Offset ; } </s>

getFrameIndexReference - This method should return the base register and offset used to reference a frame index location .


<s> const RISCVTargetLowering * getTLI ( ) const { return TLI ; } </s>

Getter for generic TargetLowering class .


<s>
MachineBasicBlock
*
RISCVTargetLowering
::
EmitInstrWithCustomInserter
(
MachineInstr
&
MI
,
MachineBasicBlock
*
MBB
)
const
{
switch
(
MI
.
getOpcode
(
)
)
{
case
RISCV
::
SELECT_CC
:
case
RISCV
::
SELECT_CC64
:
case
RISCV
::
FSELECT_CC_F
:
case
RISCV
::
FSELECT_CC_D
:
return
emitSelectCC
(
MI
,
MBB
)
;
case
RISCV
::
CALL
:
case
RISCV
::
CALLREG
:
case
RISCV
::
CALL64
:
case
RISCV
::
CALLREG64
:
return
emitCALL
(
MI
,
MBB
)
;
default
:
llvm_unreachable
(
"Unexpected instr type to insert"
)
;
}
}
</s>

This method should be implemented by targets that mark instructions with the 'usesCustomInserter ' flag .


<s> bool RISCVAsmBackend :: shouldForceRelocation ( const MCAssembler & Asm , const MCFixup & Fixup , const MCValue & Target ) { if ( Fixup . getKind ( ) >= FirstLiteralRelocationKind ) return true ; switch ( Fixup . getTargetKind ( ) ) { default : break ; case FK_Data_1 : case FK_Data_2 : case FK_Data_4 : case FK_Data_8 : if ( Target . isAbsolute ( ) ) return false ; break ; case RISCV :: fixup_riscv_got_hi20 : case RISCV :: fixup_riscv_tls_got_hi20 : case RISCV :: fixup_riscv_tls_gd_hi20 : return true ; } return STI . getFeatureBits ( ) [ RISCV :: FeatureRelax ] || ForceRelocs ; } </s>

Hook to check if a relocation is needed for some target specific reason .


<s> void RISCVConstantPoolValue :: print ( raw_ostream & O ) const { O << GV ; } </s>

print - Print a debug representation of the operand to the given stream .


<s> static rtx riscv_split_integer ( HOST_WIDE_INT val , machine_mode mode ) { unsigned HOST_WIDE_INT loval = sext_hwi ( val , 32 ) ; unsigned HOST_WIDE_INT hival = sext_hwi ( ( val - loval ) >> 32 , 32 ) ; rtx hi = gen_reg_rtx ( mode ) , lo = gen_reg_rtx ( mode ) ; riscv_move_integer ( hi , hi , hival , mode , FALSE ) ; riscv_move_integer ( lo , lo , loval , mode , FALSE ) ; hi = gen_rtx_fmt_ee ( ASHIFT , mode , hi , GEN_INT ( 32 ) ) ; hi = force_reg ( mode , hi ) ; return gen_rtx_fmt_ee ( PLUS , mode , hi , lo ) ; } </s>

Try to split a 64b integer into 32b parts , then reassemble .


<s> MVT RISCVTargetLowering :: getRegisterTypeForCallingConv ( LLVMContext & Context , CallingConv :: ID CC , EVT VT ) const { if ( VT == MVT :: f16 && Subtarget . hasStdExtF ( ) && ! Subtarget . hasStdExtZfhmin ( ) ) return MVT :: f32 ; return TargetLowering :: getRegisterTypeForCallingConv ( Context , CC , VT ) ; } </s>

Certain combinations of ABIs , Targets and features require that types are legal for some operations and not for other operations .


<s> static vl_vtype_info get_vl_vtype_info ( const insn_info * insn ) { set_info * set = nullptr ; rtx avl = :: get_avl ( insn -> rtl ( ) ) ; if ( avl && REG_P ( avl ) ) { if ( vlmax_avl_p ( avl ) && has_vl_op ( insn -> rtl ( ) ) ) set = find_access ( insn -> uses ( ) , REGNO ( get_vl ( insn -> rtl ( ) ) ) ) -> def ( ) ; else if ( ! vlmax_avl_p ( avl ) ) set = find_access ( insn -> uses ( ) , REGNO ( avl ) ) -> def ( ) ; else set = nullptr ; } uint8_t sew = get_sew ( insn -> rtl ( ) ) ; enum vlmul_type vlmul = get_vlmul ( insn -> rtl ( ) ) ; uint8_t ratio = get_attr_ratio ( insn -> rtl ( ) ) ; if ( ratio == INVALID_ATTRIBUTE ) ratio = calculate_ratio ( sew , vlmul ) ; bool ta = tail_agnostic_p ( insn -> rtl ( ) ) ; bool ma = mask_agnostic_p ( insn -> rtl ( ) ) ; int merge_op_idx = get_attr_merge_op_idx ( insn -> rtl ( ) ) ; if ( merge_op_idx != INVALID_ATTRIBUTE && satisfies_constraint_vu ( recog_data . operand [ merge_op_idx ] ) ) { ta = true ; ma = true ; } vl_vtype_info info ( avl_info ( avl , set ) , sew , vlmul , ratio , ta , ma ) ; return info ; } </s>


<s> bool isReg ( ) const override { return Kind == KindTy :: Register ; } </s>


<s> inline void function_expander :: add_integer_operand ( rtx x ) { create_integer_operand ( & m_ops [ opno ++ ] , INTVAL ( x ) ) ; } </s>


<s> const uint32_t * RISCVRegisterInfo :: getNoPreservedMask ( ) const { return CSR_NoRegs_RegMask ; } </s>

Return a register mask that clobbers everything .


<s> inline bool function_base :: use_mask_predication_p ( ) const { return true ; } </s>

We choose to return true by default since most of the intrinsics use mask predication .


<s> bool RISCVRegisterInfo :: isConstantPhysReg ( MCRegister PhysReg ) const { return PhysReg == RISCV :: X0 || PhysReg == RISCV :: VLENB ; } </s>

Returns true if PhysReg is unallocatable and constant throughout the function .


<s>
static
const
struct
riscv_cpu_info
*
riscv_parse_cpu
(
const
char
*
cpu_string
)
{
for
(
unsigned
i
=
0
;
i
<
ARRAY_SIZE
(
riscv_cpu_info_table
)
;
i
++
)
if
(
strcmp
(
riscv_cpu_info_table
[
i
]
.
name
,
cpu_string
)
==
0
)
return
riscv_cpu_info_table
+
i
;
error
(
"unknown cpu %qs for -mtune"
,
cpu_string
)
;
return
riscv_cpu_info_table
;
}
</s>

Return the riscv_cpu_info entry for the given name string .


<s>
void
RISCVInstrInfo
::
copyPhysReg
(
MachineBasicBlock
&
MBB
,
MachineBasicBlock
::
iterator
MBBI
,
const
DebugLoc
&
DL
,
MCRegister
DstReg
,
MCRegister
SrcReg
,
bool
KillSrc
)
const
{
MachineFunction
*
MF
=
MBB
.
getParent
(
)
;
const
TargetRegisterInfo
*
TRI
=
MF
->
getSubtarget
(
)
.
getRegisterInfo
(
)
;
if
(
RISCV
::
GPRRegClass
.
contains
(
DstReg
,
SrcReg
)
)
{
BuildMI
(
MBB
,
MBBI
,
DL
,
get
(
RISCV
::
ADDI
)
,
DstReg
)
.
addReg
(
SrcReg
,
getKillRegState
(
KillSrc
)
)
.
addImm
(
0
)
;
return
;
}
unsigned
Opc
;
if
(
RISCV
::
FPR32RegClass
.
contains
(
DstReg
,
SrcReg
)
)
Opc
=
RISCV
::
FSGNJ_S
;
else
if
(
RISCV
::
FPR64RegClass
.
contains
(
DstReg
,
SrcReg
)
)
Opc
=
RISCV
::
FSGNJ_D
;
else
if
(
RISCV
::
VRRegClass
.
contains
(
DstReg
,
SrcReg
)
)
{
BuildMI
(
MBB
,
MBBI
,
DL
,
get
(
RISCV
::
VMV1R_V
)
,
DstReg
)
.
addReg
(
SrcReg
,
getKillRegState
(
KillSrc
)
)
;
return
;
}
else
if
(
RISCV
::
VRM2RegClass
.
contains
(
DstReg
,
SrcReg
)
||
RISCV
::
VRM4RegClass
.
contains
(
DstReg
,
SrcReg
)
||
RISCV
::
VRM8RegClass
.
contains
(
DstReg
,
SrcReg
)
)
{
unsigned
Opcode
;
if
(
RISCV
::
VRM2RegClass
.
contains
(
DstReg
,
SrcReg
)
)
Opcode
=
RISCV
::
VMV2R_V
;
else
if
(
RISCV
::
VRM4RegClass
.
contains
(
DstReg
,
SrcReg
)
)
Opcode
=
RISCV
::
VMV4R_V
;
else
Opcode
=
RISCV
::
VMV8R_V
;
DstReg
=
TRI
->
getSubReg
(
DstReg
,
RISCV
::
sub_vrm2
)
;
SrcReg
=
TRI
->
getSubReg
(
SrcReg
,
RISCV
::
sub_vrm2
)
;
BuildMI
(
MBB
,
MBBI
,
DL
,
get
(
Opcode
)
,
DstReg
)
.
addReg
(
SrcReg
,
getKillRegState
(
KillSrc
)
)
;
return
;
}
else
{
llvm_unreachable
(
"Impossible reg-to-reg copy"
)
;
}
BuildMI
(
MBB
,
MBBI
,
DL
,
get
(
Opc
)
,
DstReg
)
.
addReg
(
SrcReg
,
getKillRegState
(
KillSrc
)
)
.
addReg
(
SrcReg
,
getKillRegState
(
KillSrc
)
)
;
}
</s>


<s> void function_expander :: add_mem_operand ( machine_mode mode , unsigned argno ) { gcc_assert ( VECTOR_MODE_P ( mode ) ) ; rtx addr = expand_normal ( CALL_EXPR_ARG ( exp , argno ) ) ; rtx mem = gen_rtx_MEM ( mode , memory_address ( mode , addr ) ) ; set_mem_align ( mem , GET_MODE_ALIGNMENT ( GET_MODE_INNER ( mode ) ) ) ; add_fixed_operand ( mem ) ; } </s>

Add a memory operand with mode MODE and address ADDR .


<s> bool th_mempair_operands_p ( rtx operands [ 4 ] , bool load_p , machine_mode mode ) { rtx mem_1 , mem_2 , reg_1 , reg_2 ; if ( load_p ) { reg_1 = operands [ 0 ] ; mem_1 = operands [ 1 ] ; reg_2 = operands [ 2 ] ; mem_2 = operands [ 3 ] ; if ( ! REG_P ( reg_1 ) || ! REG_P ( reg_2 ) ) return false ; if ( th_mempair_load_overlap_p ( reg_1 , reg_2 , mem_1 ) ) return false ; if ( th_mempair_load_overlap_p ( reg_1 , reg_2 , mem_2 ) ) return false ; } else { mem_1 = operands [ 0 ] ; reg_1 = operands [ 1 ] ; mem_2 = operands [ 2 ] ; reg_2 = operands [ 3 ] ; } if ( ! REG_P ( reg_1 ) || ! GP_REG_P ( REGNO ( reg_1 ) ) || ! REG_P ( reg_2 ) || ! GP_REG_P ( REGNO ( reg_2 ) ) ) return false ; if ( ! MEM_P ( mem_1 ) || ! MEM_P ( mem_2 ) ) return false ; if ( MEM_VOLATILE_P ( mem_1 ) || MEM_VOLATILE_P ( mem_2 ) ) return false ; if ( riscv_slow_unaligned_access_p && known_lt ( MEM_ALIGN ( mem_1 ) , GET_MODE_SIZE ( mode ) * BITS_PER_UNIT ) ) return false ; bool reversed = false ; if ( ! th_mempair_check_consecutive_mems ( mode , & mem_1 , & mem_2 , & reversed ) ) return false ; if ( ( ! reversed && ! th_mempair_operand_p ( mem_1 , mode ) ) || ( reversed && ! th_mempair_operand_p ( mem_2 , mode ) ) ) return false ; gcc_assert ( known_eq ( GET_MODE_SIZE ( GET_MODE ( mem_1 ) ) , GET_MODE_SIZE ( GET_MODE ( mem_2 ) ) ) ) ; return true ; } </s>

Given OPERANDS of consecutive load/store , check if we can merge them into load-pair or store-pair instructions . LOAD is true if they are load instructions . MODE is the mode of memory operation .


<s>
void
print
(
raw_ostream
&
OS
)
const
override
{
switch
(
Kind
)
{
case
KindTy
::
Immediate
:
OS
<<
*
getImm
(
)
;
break
;
case
KindTy
::
Register
:
OS
<<
"<register x"
;
OS
<<
getReg
(
)
<<
">"
;
break
;
case
KindTy
::
Token
:
OS
<<
"'"
<<
getToken
(
)
<<
"'"
;
break
;
case
KindTy
::
SystemRegister
:
OS
<<
"<sysreg: "
<<
getSysReg
(
)
<<
'>'
;
break
;
}
}
</s>

RISCV
"<register x"
">"
"'"
"'"
"<sysreg: "


<s>
bool
RISCVInsertVSETVLI
::
runOnMachineFunction
(
MachineFunction
&
MF
)
{
const
RISCVSubtarget
&
ST
=
MF
.
getSubtarget
<
RISCVSubtarget
>
(
)
;
if
(
!
ST
.
hasVInstructions
(
)
)
return
false
;
TII
=
ST
.
getInstrInfo
(
)
;
MRI
=
&
MF
.
getRegInfo
(
)
;
assert
(
BlockInfo
.
empty
(
)
&&
"Expect empty block infos"
)
;
BlockInfo
.
resize
(
MF
.
getNumBlockIDs
(
)
)
;
bool
HaveVectorOp
=
false
;
for
(
const
MachineBasicBlock
&
MBB
:
MF
)
HaveVectorOp
|=
computeVLVTYPEChanges
(
MBB
)
;
if
(
HaveVectorOp
)
{
for
(
const
MachineBasicBlock
&
MBB
:
MF
)
{
WorkList
.
push
(
&
MBB
)
;
BlockInfo
[
MBB
.
getNumber
(
)
]
.
InQueue
=
true
;
}
while
(
!
WorkList
.
empty
(
)
)
{
const
MachineBasicBlock
&
MBB
=
*
WorkList
.
front
(
)
;
WorkList
.
pop
(
)
;
computeIncomingVLVTYPE
(
MBB
)
;
}
for
(
MachineBasicBlock
&
MBB
:
MF
)
emitVSETVLIs
(
MBB
)
;
}
BlockInfo
.
clear
(
)
;
return
HaveVectorOp
;
}
</s>

runOnMachineFunction - Emit the function body .

RISCV
RISCV
RISCV
RISCV
"Expect empty block infos"


<s> static void riscv_save_restore_reg ( machine_mode mode , int regno , HOST_WIDE_INT offset , riscv_save_restore_fn fn ) { rtx mem ; mem = gen_frame_mem ( mode , plus_constant ( Pmode , stack_pointer_rtx , offset ) ) ; fn ( gen_rtx_REG ( mode , regno ) , mem ) ; } </s>

Use FN to save or restore register REGNO . MODE is the register 's mode and OFFSET is the offset of its save slot from the current stack pointer .


"eliminateFrameIndex currently requires hasFP"

"Frame offsets outside of the signed 12-bit range not supported"

This method must be overriden to eliminate abstract frame indices from instructions which may use them .


<s> unsigned RISCVTargetLowering :: getNumRegistersForCallingConv ( LLVMContext & Context , CallingConv :: ID CC , EVT VT ) const { if ( VT == MVT :: f16 && Subtarget . hasStdExtF ( ) && ! Subtarget . hasStdExtZfhmin ( ) ) return 1 ; return TargetLowering :: getNumRegistersForCallingConv ( Context , CC , VT ) ; } </s>

Certain targets require unusual breakdowns of certain types .


<s> TargetLowering :: AtomicExpansionKind RISCVTargetLowering :: shouldExpandAtomicCmpXchgInIR ( AtomicCmpXchgInst * CI ) const { unsigned Size = CI -> getCompareOperand ( ) -> getType ( ) -> getPrimitiveSizeInBits ( ) ; if ( ( Size == 8 || Size == 16 ) && ! RISCVABI :: isCheriPureCapABI ( Subtarget . getTargetABI ( ) ) ) return AtomicExpansionKind :: MaskedIntrinsic ; return AtomicExpansionKind :: None ; } </s>

Returns how the given atomic cmpxchg should be expanded by the IR-level AtomicExpand pass .


<s> rtx riscv_subword ( rtx op , bool high_p ) { unsigned int byte = ( high_p != BYTES_BIG_ENDIAN ) ? UNITS_PER_WORD : 0 ; machine_mode mode = GET_MODE ( op ) ; if ( mode == VOIDmode ) mode = TARGET_64BIT ? TImode : DImode ; if ( MEM_P ( op ) ) return adjust_address ( op , word_mode , byte ) ; if ( REG_P ( op ) ) gcc_assert ( ! FP_REG_RTX_P ( op ) ) ; return simplify_gen_subreg ( word_mode , op , mode , byte ) ; } </s>

Return one word of double-word value OP . HIGH_P is true to select the high part or false to select the low part .


<s> bool RISCVTargetLowering :: isLegalAddressingMode ( const DataLayout & DL , const AddrMode & AM , Type * Ty , unsigned AS , Instruction * I ) const { if ( AM . BaseGV ) return false ; if ( ! isInt < 12 > ( AM . BaseOffs ) ) return false ; switch ( AM . Scale ) { case 0 : break ; case 1 : if ( ! AM . HasBaseReg ) break ; return false ; default : return false ; } return true ; } </s>

isLegalAddressingMode - Return true if the addressing mode represented by AM is legal for this target , for a load/store of the specified type .


<s> bool isValid ( ) const { return State != Uninitialized ; } </s>

Returns true if this iterator is still pointing at a valid entry .


<s>
MCOperand
RISCVMCInstLower
::
lowerOperand
(
const
MachineOperand
&
MO
)
const
{
switch
(
MO
.
getType
(
)
)
{
default
:
llvm_unreachable
(
"unknown operand type"
)
;
case
MachineOperand
::
MO_Register
:
if
(
MO
.
isImplicit
(
)
)
return
MCOperand
(
)
;
return
MCOperand
::
createReg
(
MO
.
getReg
(
)
)
;
case
MachineOperand
::
MO_Immediate
:
return
MCOperand
::
createImm
(
MO
.
getImm
(
)
)
;
case
MachineOperand
::
MO_MachineBasicBlock
:
return
lowerSymbolOperand
(
MO
,
MO
.
getMBB
(
)
->
getSymbol
(
)
,
0
)
;
case
MachineOperand
::
MO_GlobalAddress
:
return
lowerSymbolOperand
(
MO
,
AsmPrinter
.
getSymbol
(
MO
.
getGlobal
(
)
)
,
MO
.
getOffset
(
)
)
;
case
MachineOperand
::
MO_ExternalSymbol
:
{
StringRef
Name
=
MO
.
getSymbolName
(
)
;
return
lowerSymbolOperand
(
MO
,
AsmPrinter
.
GetExternalSymbolSymbol
(
Name
)
,
MO
.
getOffset
(
)
)
;
}
case
MachineOperand
::
MO_JumpTableIndex
:
return
lowerSymbolOperand
(
MO
,
AsmPrinter
.
GetJTISymbol
(
MO
.
getIndex
(
)
)
,
0
)
;
case
MachineOperand
::
MO_ConstantPoolIndex
:
return
lowerSymbolOperand
(
MO
,
AsmPrinter
.
GetCPISymbol
(
MO
.
getIndex
(
)
)
,
MO
.
getOffset
(
)
)
;
case
MachineOperand
::
MO_BlockAddress
:
{
const
BlockAddress
*
BA
=
MO
.
getBlockAddress
(
)
;
return
lowerSymbolOperand
(
MO
,
AsmPrinter
.
GetBlockAddressSymbol
(
BA
)
,
MO
.
getOffset
(
)
)
;
}
}
}
</s>

Wrapper for MCInstLowering.lowerOperand ( ) for the tblgen'erated pseudo lowering .


<s> bool riscv_shamt_matches_mask_p ( int shamt , HOST_WIDE_INT mask ) { return shamt == ctz_hwi ( mask ) ; } </s>

Return true if a shift-amount matches the trailing cleared bits on a bitmask .


<s> bool riscv_symbolic_constant_p ( rtx x , enum riscv_symbol_type * symbol_type ) { rtx offset ; split_const ( x , & x , & offset ) ; if ( UNSPEC_ADDRESS_P ( x ) ) { * symbol_type = UNSPEC_ADDRESS_TYPE ( x ) ; x = UNSPEC_ADDRESS ( x ) ; } else if ( GET_CODE ( x ) == SYMBOL_REF || GET_CODE ( x ) == LABEL_REF ) * symbol_type = riscv_classify_symbol ( x ) ; else return false ; if ( offset == const0_rtx ) return true ; switch ( * symbol_type ) { case SYMBOL_ABSOLUTE : case SYMBOL_PCREL : case SYMBOL_TLS_LE : return sext_hwi ( INTVAL ( offset ) , 32 ) == INTVAL ( offset ) ; default : return false ; } } </s>

Return true if X is a symbolic constant . If it is , store the type of the symbol in * SYMBOL_TYPE .


<s> const uint16_t * RISCVRegisterInfo :: getCalleeSavedRegs ( const MachineFunction * MF ) const { if ( Subtarget . isRV64 ( ) ) if ( Subtarget . hasD ( ) ) return CSR_RV64D_SaveList ; else if ( Subtarget . hasF ( ) ) return CSR_RV64F_SaveList ; else return CSR_RV64_SaveList ; else if ( Subtarget . hasD ( ) ) return CSR_RV32D_SaveList ; else if ( Subtarget . hasF ( ) ) return CSR_RV32F_SaveList ; else return CSR_RV32_SaveList ; } </s>


"ReadCycleWrite is only to be used on riscv32"

This method should be implemented by targets that mark instructions with the 'usesCustomInserter ' flag .


<s> poly_int64 riscv_v_adjust_nunits ( machine_mode mode , int scale ) { if ( riscv_v_ext_vector_mode_p ( mode ) ) return riscv_vector_chunks * scale ; return scale ; } </s>

Call from ADJUST_NUNITS in riscv-modes.def . Return the correct NUNITS size for corresponding machine_mode .


<s> bool RISCVTargetLowering :: hasAndNotCompare ( SDValue Y ) const { EVT VT = Y . getValueType ( ) ; if ( VT . isVector ( ) ) return false ; return ( Subtarget . hasStdExtZbb ( ) || Subtarget . hasStdExtZbp ( ) || Subtarget . hasStdExtZbkb ( ) ) && ! isa < ConstantSDNode > ( Y ) ; } </s>

Return true if the target should transform : ( X & Y ) == Y � ? ( ~X & Y ) == 0 ( X & Y ) ! = Y � ? ( ~X & Y ) ! = 0 .


<s> inline void function_expander :: add_all_one_mask_operand ( machine_mode mode ) { add_input_operand ( mode , CONSTM1_RTX ( mode ) ) ; } </s>

Since we may normalize vop/vop_tu/vop_m/vop_tumu .. into a single patter . We add a fake all true mask for the intrinsics that do n't need a real mask .


<s> BitVector RISCVRegisterInfo :: getReservedRegs ( const MachineFunction & MF ) const { BitVector Reserved ( getNumRegs ( ) ) ; markSuperRegs ( Reserved , RISCV :: X0 ) ; markSuperRegs ( Reserved , RISCV :: X1 ) ; markSuperRegs ( Reserved , RISCV :: X2 ) ; markSuperRegs ( Reserved , RISCV :: X3 ) ; markSuperRegs ( Reserved , RISCV :: X4 ) ; markSuperRegs ( Reserved , RISCV :: X8 ) ; assert ( checkAllSuperRegsMarked ( Reserved ) ) ; return Reserved ; } </s>

getReservedRegs - Returns a bitset indexed by physical register number indicating if a register is a special register that has particular uses and should be considered unavailable at all times , e.g .


<s> bool isToken ( ) const override { return Kind == KindToken ; } </s>


<s> void pass_shorten_memrefs :: transform ( regno_map * m , basic_block bb ) { rtx_insn * insn ; FOR_BB_INSNS ( bb , insn ) { if ( ! NONJUMP_INSN_P ( insn ) ) continue ; rtx pat = PATTERN ( insn ) ; if ( GET_CODE ( pat ) != SET ) continue ; start_sequence ( ) ; for ( int i = 0 ; i < 2 ; i ++ ) { rtx mem = XEXP ( pat , i ) ; rtx addr ; bool extend = false ; if ( get_si_mem_base_reg ( mem , & addr , & extend ) ) { HOST_WIDE_INT regno = REGNO ( XEXP ( addr , 0 ) ) ; if ( i == 0 ) { if ( XEXP ( pat , 1 ) == CONST0_RTX ( GET_MODE ( XEXP ( pat , 1 ) ) ) ) continue ; } if ( m -> get_or_insert ( regno ) > 3 ) { if ( extend ) { addr = targetm . legitimize_address ( addr , addr , GET_MODE ( XEXP ( mem , 0 ) ) ) ; XEXP ( XEXP ( pat , i ) , 0 ) = replace_equiv_address ( XEXP ( mem , 0 ) , addr ) ; } else { addr = targetm . legitimize_address ( addr , addr , GET_MODE ( mem ) ) ; XEXP ( pat , i ) = replace_equiv_address ( mem , addr ) ; } df_insn_rescan ( insn ) ; } } } rtx_insn * seq = get_insns ( ) ; end_sequence ( ) ; emit_insn_before ( seq , insn ) ; } } </s>

Convert BASE + LARGE_OFFSET to NEW_BASE + SMALL_OFFSET for each load/store with a base reg referenced at least 4 times .


<s> void riscv_cpu_cpp_builtins ( cpp_reader * pfile ) { builtin_define ( "__riscv" ) ; if ( TARGET_RVC ) builtin_define ( "__riscv_compressed" ) ; if ( TARGET_ATOMIC ) builtin_define ( "__riscv_atomic" ) ; if ( TARGET_MUL ) builtin_define ( "__riscv_mul" ) ; if ( TARGET_DIV ) builtin_define ( "__riscv_div" ) ; if ( TARGET_DIV && TARGET_MUL ) builtin_define ( "__riscv_muldiv" ) ; builtin_define_with_int_value ( "__riscv_xlen" , UNITS_PER_WORD * 8 ) ; if ( TARGET_HARD_FLOAT ) builtin_define_with_int_value ( "__riscv_flen" , UNITS_PER_FP_REG * 8 ) ; if ( TARGET_HARD_FLOAT && TARGET_FDIV ) { builtin_define ( "__riscv_fdiv" ) ; builtin_define ( "__riscv_fsqrt" ) ; } switch ( riscv_abi ) { case ABI_ILP32 : case ABI_LP64 : builtin_define ( "__riscv_float_abi_soft" ) ; break ; case ABI_ILP32F : case ABI_LP64F : builtin_define ( "__riscv_float_abi_single" ) ; break ; case ABI_ILP32D : case ABI_LP64D : builtin_define ( "__riscv_float_abi_double" ) ; break ; } switch ( riscv_cmodel ) { case CM_MEDLOW : builtin_define ( "__riscv_cmodel_medlow" ) ; break ; case CM_MEDANY : builtin_define ( "__riscv_cmodel_medany" ) ; break ; case CM_PIC : builtin_define ( "__riscv_cmodel_pic" ) ; break ; } } </s>


<s> void RISCVELFTargetObjectFile :: Initialize ( MCContext & Ctx , const TargetMachine & TM ) { TargetLoweringObjectFileELF :: Initialize ( Ctx , TM ) ; InitializeELF ( TM . Options . UseInitArray ) ; SmallDataSection = getContext ( ) . getELFSection ( ".sdata" , ELF :: SHT_PROGBITS , ELF :: SHF_WRITE | ELF :: SHF_ALLOC ) ; SmallBSSSection = getContext ( ) . getELFSection ( ".sbss" , ELF :: SHT_NOBITS , ELF :: SHF_WRITE | ELF :: SHF_ALLOC ) ; } </s>

This method must be called before any actual lowering is done .


<s> bool shouldConvertConstantLoadToIntImm ( const APInt & Imm , Type * Ty ) const override { return true ; } </s>

Returns true if it is beneficial to convert a load of a constant to just the constant itself .


<s> const RISCVRegisterInfo & getRegisterInfo ( ) const { return RI ; } </s>

getRegisterInfo - TargetInstrInfo is a superset of MRegister info .


"getIntImmCost can only estimate cost of materialising integers"

Calculate the cost of materializing a 64-bit value .


<s> static bool riscv_hard_regno_mode_ok ( unsigned int regno , machine_mode mode ) { unsigned int nregs = riscv_hard_regno_nregs ( regno , mode ) ; if ( GP_REG_P ( regno ) ) { if ( riscv_v_ext_vector_mode_p ( mode ) ) return false ; if ( ! GP_REG_P ( regno + nregs - 1 ) ) return false ; } else if ( FP_REG_P ( regno ) ) { if ( riscv_v_ext_vector_mode_p ( mode ) ) return false ; if ( ! FP_REG_P ( regno + nregs - 1 ) ) return false ; if ( GET_MODE_CLASS ( mode ) != MODE_FLOAT && GET_MODE_CLASS ( mode ) != MODE_COMPLEX_FLOAT ) return false ; if ( GET_MODE_UNIT_SIZE ( mode ) > UNITS_PER_FP_REG || ( ! call_used_or_fixed_reg_p ( regno ) && GET_MODE_UNIT_SIZE ( mode ) > UNITS_PER_FP_ARG ) ) return false ; } else if ( V_REG_P ( regno ) ) { if ( ! riscv_v_ext_vector_mode_p ( mode ) ) return false ; if ( ! V_REG_P ( regno + nregs - 1 ) ) return false ; int lmul = 1 ; if ( known_gt ( GET_MODE_SIZE ( mode ) , UNITS_PER_V_REG ) ) lmul = exact_div ( GET_MODE_SIZE ( mode ) , UNITS_PER_V_REG ) . to_constant ( ) ; if ( lmul != 1 ) return ( ( regno % lmul ) == 0 ) ; } else if ( regno == VL_REGNUM || regno == VTYPE_REGNUM ) return true ; else return false ; for ( unsigned i = 1 ; i < nregs ; i ++ ) if ( call_used_or_fixed_reg_p ( regno ) != call_used_or_fixed_reg_p ( regno + i ) ) return false ; if ( ! TARGET_64BIT && TARGET_ZDINX ) { if ( GET_MODE_CLASS ( mode ) == MODE_FLOAT && GET_MODE_UNIT_SIZE ( mode ) == GET_MODE_SIZE ( DFmode ) ) return ! ( regno & 1 ) ; } return true ; } </s>


<s> bool RISCVTargetLowering :: CanLowerReturn ( CallingConv :: ID CallConv , MachineFunction & MF , bool IsVarArg , const SmallVectorImpl < ISD :: OutputArg > & Outs , LLVMContext & Context ) const { SmallVector < CCValAssign , 16 > RVLocs ; CCState CCInfo ( CallConv , IsVarArg , MF , RVLocs , Context ) ; for ( unsigned i = 0 , e = Outs . size ( ) ; i != e ; ++ i ) { MVT VT = Outs [ i ] . VT ; ISD :: ArgFlagsTy ArgFlags = Outs [ i ] . Flags ; RISCVABI :: ABI ABI = MF . getSubtarget < RISCVSubtarget > ( ) . getTargetABI ( ) ; if ( CC_RISCV ( MF . getDataLayout ( ) , ABI , i , VT , VT , CCValAssign :: Full , ArgFlags , CCInfo , true , true , nullptr ) ) return false ; } return true ; } </s>

This hook should be implemented to check whether the return values described by the Outs array can fit into the return registers .

RISCV RISCV ISD::OutputArg 16 0 ISD::ArgFlagsTy RISCVABI::ABI RISCV RISCV


"frame pointer should not have been eliminated"

"SecondSPAdjustAmount should be greater than zero"


<s> static rtx riscv_add_offset ( rtx temp , rtx reg , HOST_WIDE_INT offset ) { if ( ! SMALL_OPERAND ( offset ) ) { rtx high ; high = gen_int_mode ( CONST_HIGH_PART ( offset ) , Pmode ) ; offset = CONST_LOW_PART ( offset ) ; high = riscv_force_temporary ( temp , high ) ; reg = riscv_force_temporary ( temp , gen_rtx_PLUS ( Pmode , high , reg ) ) ; } return plus_constant ( Pmode , reg , offset ) ; } </s>

Return a legitimate address for REG + OFFSET . TEMP is as for riscv_force_temporary ; it is only needed when OFFSET is not a SMALL_OPERAND .


<s> static HOST_WIDE_INT riscv_stack_align ( HOST_WIDE_INT value ) { return RISCV_STACK_ALIGN ( value ) ; } </s>


<s> static bool riscv_can_change_mode_class ( machine_mode , machine_mode , reg_class_t rclass ) { return ! reg_classes_intersect_p ( FP_REGS , rclass ) ; } </s>


<s> void riscv_run_selftests ( void ) { run_poly_int_selftests ( ) ; run_const_vector_selftests ( ) ; run_broadcast_selftests ( ) ; } </s>


<s> static unsigned riscv_save_libcall_count ( unsigned mask ) { for ( unsigned n = GP_REG_LAST ; n > GP_REG_FIRST ; n -- ) if ( BITSET_P ( mask , n ) ) return CALLEE_SAVED_REG_NUMBER ( n ) + 1 ; abort ( ) ; } </s>

Determine which GPR save/restore routine to call .


<s> static bool extract_base_offset_in_addr ( rtx mem , rtx * base , rtx * offset ) { rtx addr ; gcc_assert ( MEM_P ( mem ) ) ; addr = XEXP ( mem , 0 ) ; if ( REG_P ( addr ) ) { * base = addr ; * offset = const0_rtx ; return true ; } if ( GET_CODE ( addr ) == PLUS && REG_P ( XEXP ( addr , 0 ) ) && CONST_INT_P ( XEXP ( addr , 1 ) ) ) { * base = XEXP ( addr , 0 ) ; * offset = XEXP ( addr , 1 ) ; return true ; } * base = NULL_RTX ; * offset = NULL_RTX ; return false ; } </s>

If MEM is in the form of `` base+offset '' , extract the two parts of address and set to BASE and OFFSET , otherwise return false after clearing BASE and OFFSET .


<s> static bool mask_agnostic_p ( rtx_insn * rinsn ) { extract_insn_cached ( rinsn ) ; int ma = get_attr_ma ( rinsn ) ; return ma == INVALID_ATTRIBUTE ? get_default_ma ( ) : IS_AGNOSTIC ( ma ) ; } </s>


"Frame offsets outside of the signed 32-bit range not supported"

This method must be overriden to eliminate abstract frame indices from instructions which may use them .


"Not all fixup kinds added to Infos array"


<s> static bool riscv_slow_unaligned_access ( machine_mode , unsigned int ) { return riscv_slow_unaligned_access_p ; } </s>


<s> static void riscv_adjust_block_mem ( rtx mem , unsigned HOST_WIDE_INT length , rtx * loop_reg , rtx * loop_mem ) { * loop_reg = copy_addr_to_reg ( XEXP ( mem , 0 ) ) ; * loop_mem = change_address ( mem , BLKmode , * loop_reg ) ; set_mem_align ( * loop_mem , MIN ( MEM_ALIGN ( mem ) , length * BITS_PER_UNIT ) ) ; } </s>

Helper function for doing a loop-based block operation on memory reference MEM . Each iteration of the loop will operate on LENGTH bytes of MEM . Create a new base register for use within the loop and point it to the start of MEM . Create a new memory reference that uses this register . Store them in * LOOP_REG and * LOOP_MEM respectively .


<s>
static
void
riscv_file_start
(
void
)
{
default_file_start
(
)
;
fprintf
(
asm_out_file
,
"\t.option %spic\n"
,
(
flag_pic
""
:
"no"
)
)
;
if
(
!
riscv_mrelax
)
fprintf
(
asm_out_file
,
"\t.option norelax\n"
)
;
if
(
riscv_mcsr_check
)
fprintf
(
asm_out_file
,
"\t.option csr-check\n"
)
;
if
(
riscv_emit_attribute_p
)
riscv_emit_attribute
(
)
;
}
</s>

riscv
"\t.option %spic\n"
""
"no"
"\t.option norelax\n"
"\t.option csr-check\n"


<s> int riscv_address_insns ( rtx x , enum machine_mode mode , bool might_split_p ) { struct riscv_address_info addr ; int n = 1 ; if ( ! riscv_classify_address ( & addr , x , mode , false ) ) return 0 ; if ( mode != BLKmode && might_split_p ) n += ( GET_MODE_SIZE ( mode ) + UNITS_PER_WORD - 1 ) / UNITS_PER_WORD ; if ( addr . type == ADDRESS_LO_SUM ) n += riscv_symbol_insns ( addr . symbol_type ) - 1 ; return n ; } </s>

Return the number of instructions needed to load or store a value of mode MODE at address X . Return 0 if X is n't valid for MODE . Assume that multiword moves may need to be split into word moves if MIGHT_SPLIT_P , otherwise assume that a single load or store is enough .


<s> static rtx riscv_force_binary ( enum machine_mode mode , enum rtx_code code , rtx x , rtx y ) { return riscv_emit_binary ( code , gen_reg_rtx ( mode ) , x , y ) ; } </s>

Compute ( CODE X Y ) and store the result in a new register of mode MODE . Return that new register .


<s> static int riscv_build_integer_1 ( struct riscv_integer_op codes [ RISCV_MAX_INTEGER_OPS ] , HOST_WIDE_INT value , enum machine_mode mode ) { HOST_WIDE_INT low_part = CONST_LOW_PART ( value ) ; int cost = RISCV_MAX_INTEGER_OPS + 1 , alt_cost ; struct riscv_integer_op alt_codes [ RISCV_MAX_INTEGER_OPS ] ; if ( SMALL_OPERAND ( value ) || LUI_OPERAND ( value ) ) { codes [ 0 ] . code = UNKNOWN ; codes [ 0 ] . value = value ; return 1 ; } if ( low_part != 0 && ( mode != HImode || value - low_part <= ( ( 1 << ( GET_MODE_BITSIZE ( HImode ) - 1 ) ) - 1 ) ) ) { alt_cost = 1 + riscv_build_integer_1 ( alt_codes , value - low_part , mode ) ; if ( alt_cost < cost ) { alt_codes [ alt_cost - 1 ] . code = PLUS ; alt_codes [ alt_cost - 1 ] . value = low_part ; memcpy ( codes , alt_codes , sizeof ( alt_codes ) ) ; cost = alt_cost ; } } if ( cost > 2 && ( low_part < 0 || mode == HImode ) ) { alt_cost = 1 + riscv_build_integer_1 ( alt_codes , value ^ low_part , mode ) ; if ( alt_cost < cost ) { alt_codes [ alt_cost - 1 ] . code = XOR ; alt_codes [ alt_cost - 1 ] . value = low_part ; memcpy ( codes , alt_codes , sizeof ( alt_codes ) ) ; cost = alt_cost ; } } if ( cost > 2 && ( value & 1 ) == 0 ) { int shift = ctz_hwi ( value ) ; unsigned HOST_WIDE_INT x = value ; x = sext_hwi ( x >> shift , HOST_BITS_PER_WIDE_INT - shift ) ; if ( shift > IMM_BITS && ! SMALL_OPERAND ( x ) && LUI_OPERAND ( x << IMM_BITS ) ) shift -= IMM_BITS , x <<= IMM_BITS ; alt_cost = 1 + riscv_build_integer_1 ( alt_codes , x , mode ) ; if ( alt_cost < cost ) { alt_codes [ alt_cost - 1 ] . code = ASHIFT ; alt_codes [ alt_cost - 1 ] . value = shift ; memcpy ( codes , alt_codes , sizeof ( alt_codes ) ) ; cost = alt_cost ; } } gcc_assert ( cost <= RISCV_MAX_INTEGER_OPS ) ; return cost ; } </s>

Helper function for riscv_build_integer ; arguments are as for riscv_build_integer .


<s> void RISCVInstPrinter :: printInst ( const MCInst * MI , raw_ostream & O , StringRef Annot , const MCSubtargetInfo & STI ) { if ( NoAliases || ! printAliasInstr ( MI , STI , O ) ) printInstruction ( MI , STI , O ) ; printAnnotation ( O , Annot ) ; } </s>

Print the specified MCInst to the specified raw_ostream .


<s>
virtual
const
char
*
getPassName
(
)
const
{
return
"RISCV Branch Selector"
;
}
</s>

getPassName - Return a nice clean name for a pass .


<s> unsigned RISCVTargetLowering :: ComputeNumSignBitsForTargetNode ( SDValue Op , const APInt & DemandedElts , const SelectionDAG & DAG , unsigned Depth ) const { switch ( Op . getOpcode ( ) ) { default : break ; case RISCVISD :: SLLW : case RISCVISD :: SRAW : case RISCVISD :: SRLW : case RISCVISD :: DIVW : case RISCVISD :: DIVUW : case RISCVISD :: REMUW : return 33 ; } return 1 ; } </s>

Determine the number of bits in the operation that are sign bits .

RISCV RISCV RISCVISD::SLLW RISCVISD::SRAW RISCVISD::SRLW RISCVISD::DIVW RISCVISD::DIVUW RISCVISD::REMUW 33 1


<s> static inline VConstraintType getConstraint ( uint64_t TSFlags ) { return static_cast < VConstraintType > ( ( TSFlags & ConstraintMask ) >> ConstraintShift ) ; } </s>

Fetch condition in the form of PredicateConstraint , if possible .


<s> void RISCVFrameLowering :: determineCalleeSaves ( MachineFunction & MF , BitVector & SavedRegs , RegScavenger * RS ) const { TargetFrameLowering :: determineCalleeSaves ( MF , SavedRegs , RS ) ; if ( hasFP ( MF ) ) { if ( RISCVABI :: isCheriPureCapABI ( STI . getTargetABI ( ) ) ) { SavedRegs . set ( RISCV :: C1 ) ; SavedRegs . set ( RISCV :: C8 ) ; } else { SavedRegs . set ( RISCV :: X1 ) ; SavedRegs . set ( RISCV :: X8 ) ; } } if ( hasBP ( MF ) ) SavedRegs . set ( RISCVABI :: getBPReg ( STI . getTargetABI ( ) ) ) ; MachineFrameInfo & MFI = MF . getFrameInfo ( ) ; if ( MF . getFunction ( ) . hasFnAttribute ( "interrupt" ) && MFI . hasCalls ( ) ) { static const MCPhysReg CSGPRs [ ] = { RISCV :: X1 , RISCV :: X5 , RISCV :: X6 , RISCV :: X7 , RISCV :: X10 , RISCV :: X11 , RISCV :: X12 , RISCV :: X13 , RISCV :: X14 , RISCV :: X15 , RISCV :: X16 , RISCV :: X17 , RISCV :: X28 , RISCV :: X29 , RISCV :: X30 , RISCV :: X31 , 0 } ; static const MCPhysReg CSGPCRs [ ] = { RISCV :: C1 , RISCV :: C5 , RISCV :: C6 , RISCV :: C7 , RISCV :: C10 , RISCV :: C11 , RISCV :: C12 , RISCV :: C13 , RISCV :: C14 , RISCV :: C15 , RISCV :: C16 , RISCV :: C17 , RISCV :: C28 , RISCV :: C29 , RISCV :: C30 , RISCV :: C31 , 0 } ; ArrayRef < MCPhysReg > CSRegs ; if ( RISCVABI :: isCheriPureCapABI ( STI . getTargetABI ( ) ) ) CSRegs = CSGPCRs ; else CSRegs = CSGPRs ; for ( unsigned i = 0 ; CSRegs [ i ] ; ++ i ) SavedRegs . set ( CSRegs [ i ] ) ; if ( MF . getSubtarget < RISCVSubtarget > ( ) . hasStdExtF ( ) ) { const MCPhysReg * Regs = MF . getRegInfo ( ) . getCalleeSavedRegs ( ) ; for ( unsigned i = 0 ; Regs [ i ] ; ++ i ) if ( RISCV :: FPR16RegClass . contains ( Regs [ i ] ) || RISCV :: FPR32RegClass . contains ( Regs [ i ] ) || RISCV :: FPR64RegClass . contains ( Regs [ i ] ) ) SavedRegs . set ( Regs [ i ] ) ; } } } </s>

This method determines which of the registers reported by TargetRegisterInfo : :getCalleeSavedRegs ( ) should actually get saved .


<s> machine_mode function_expander :: mask_mode ( void ) const { vector_type_index mask_type_index = function_types [ type . index ] . type_indexes [ RVV_BASE_mask ] ; return TYPE_MODE ( builtin_types [ mask_type_index ] . vector ) ; } </s>

Return the machine_mode of the corresponding mask type .


<s> static bool has_vl_op ( rtx_insn * rinsn ) { return recog_memoized ( rinsn ) >= 0 && get_attr_has_vl_op ( rinsn ) ; } </s>

Return true if it is an RVV instruction depends on VL global status register .


<s>
SDValue
RISCVTargetLowering
::
LowerOperation
(
SDValue
Op
,
SelectionDAG
&
DAG
)
const
{
switch
(
Op
.
getOpcode
(
)
)
{
default
:
report_fatal_error
(
"unimplemented operand"
)
;
case
ISD
::
GlobalAddress
:
return
lowerGlobalAddress
(
Op
,
DAG
)
;
case
ISD
::
BlockAddress
:
return
lowerBlockAddress
(
Op
,
DAG
)
;
case
ISD
::
ConstantPool
:
return
lowerConstantPool
(
Op
,
DAG
)
;
case
ISD
::
GlobalTLSAddress
:
return
lowerGlobalTLSAddress
(
Op
,
DAG
)
;
case
ISD
::
SELECT
:
return
lowerSELECT
(
Op
,
DAG
)
;
case
ISD
::
VASTART
:
return
lowerVASTART
(
Op
,
DAG
)
;
case
ISD
::
FRAMEADDR
:
return
lowerFRAMEADDR
(
Op
,
DAG
)
;
case
ISD
::
RETURNADDR
:
return
lowerRETURNADDR
(
Op
,
DAG
)
;
case
ISD
::
SHL_PARTS
:
return
lowerShiftLeftParts
(
Op
,
DAG
)
;
case
ISD
::
SRA_PARTS
:
return
lowerShiftRightParts
(
Op
,
DAG
,
true
)
;
case
ISD
::
SRL_PARTS
:
return
lowerShiftRightParts
(
Op
,
DAG
,
false
)
;
case
ISD
::
BITCAST
:
{
assert
(
Subtarget
.
is64Bit
(
)
&&
Subtarget
.
hasStdExtF
(
)
&&
"Unexpected custom legalisation"
)
;
SDLoc
DL
(
Op
)
;
SDValue
Op0
=
Op
.
getOperand
(
0
)
;
if
(
Op
.
getValueType
(
)
!=
MVT
::
f32
||
Op0
.
getValueType
(
)
!=
MVT
::
i32
)
return
SDValue
(
)
;
SDValue
NewOp0
=
DAG
.
getNode
(
ISD
::
ANY_EXTEND
,
DL
,
MVT
::
i64
,
Op0
)
;
SDValue
FPConv
=
DAG
.
getNode
(
RISCVISD
::
FMV_W_X_RV64
,
DL
,
MVT
::
f32
,
NewOp0
)
;
return
FPConv
;
}
}
}
</s>

LowerOperation - Provide custom lowering hooks for some operations .


"loadRegFromStackSlot didn't insert any code!"

restoreCalleeSavedRegisters - Issues instruction ( s ) to restore all callee saved registers and returns true if it is n't possible / profitable to do so by issuing a series of load instructions via loadRegToStackSlot ( ) .


<s> static rtx riscv_expand_builtin_direct ( enum insn_code icode , rtx target , tree exp , bool has_target_p ) { struct expand_operand ops [ MAX_RECOG_OPERANDS ] ; int opno = 0 ; if ( has_target_p ) create_output_operand ( & ops [ opno ++ ] , target , TYPE_MODE ( TREE_TYPE ( exp ) ) ) ; gcc_assert ( opno + call_expr_nargs ( exp ) == insn_data [ icode ] . n_generator_args ) ; for ( int argno = 0 ; argno < call_expr_nargs ( exp ) ; argno ++ ) riscv_prepare_builtin_arg ( & ops [ opno ++ ] , exp , argno ) ; return riscv_expand_builtin_insn ( icode , opno , ops , has_target_p ) ; } </s>

Expand a RISCV_BUILTIN_DIRECT or RISCV_BUILTIN_DIRECT_NO_TARGET function ; HAS_TARGET_P says which . EXP is the CALL_EXPR that calls the function and ICODE is the code of the associated .md pattern . TARGET , if nonnull , suggests a good place to put the result .


<s> static rtx riscv_function_arg ( cumulative_args_t cum_v , const function_arg_info & arg ) { CUMULATIVE_ARGS * cum = get_cumulative_args ( cum_v ) ; struct riscv_arg_info info ; if ( arg . end_marker_p ( ) ) return NULL ; return riscv_get_arg_info ( & info , cum , arg . mode , arg . type , arg . named , false ) ; } </s>


"RegScavenger required for long branching"

"new block should be inserted for expanding unconditional branch"

"Branch offsets outside of the signed 32-bit range not supported"

Insert an unconditional indirect branch at the end of MBB to NewDestBB .


<s> void riscv_cpu_cpp_builtins ( cpp_reader * pfile ) { builtin_define ( "__riscv" ) ; if ( TARGET_RVC ) builtin_define ( "__riscv_compressed" ) ; if ( TARGET_RVE ) builtin_define ( "__riscv_32e" ) ; if ( TARGET_ATOMIC ) builtin_define ( "__riscv_atomic" ) ; if ( TARGET_MUL ) builtin_define ( "__riscv_mul" ) ; if ( TARGET_DIV ) builtin_define ( "__riscv_div" ) ; if ( TARGET_DIV && TARGET_MUL ) builtin_define ( "__riscv_muldiv" ) ; builtin_define_with_int_value ( "__riscv_xlen" , UNITS_PER_WORD * 8 ) ; if ( TARGET_HARD_FLOAT ) builtin_define_with_int_value ( "__riscv_flen" , UNITS_PER_FP_REG * 8 ) ; if ( ( TARGET_HARD_FLOAT || TARGET_ZFINX ) && TARGET_FDIV ) { builtin_define ( "__riscv_fdiv" ) ; builtin_define ( "__riscv_fsqrt" ) ; } switch ( riscv_abi ) { case ABI_ILP32E : builtin_define ( "__riscv_abi_rve" ) ; gcc_fallthrough ( ) ; case ABI_ILP32 : case ABI_LP64 : builtin_define ( "__riscv_float_abi_soft" ) ; break ; case ABI_ILP32F : case ABI_LP64F : builtin_define ( "__riscv_float_abi_single" ) ; break ; case ABI_ILP32D : case ABI_LP64D : builtin_define ( "__riscv_float_abi_double" ) ; break ; } switch ( riscv_cmodel ) { case CM_MEDLOW : builtin_define ( "__riscv_cmodel_medlow" ) ; break ; case CM_PIC : case CM_MEDANY : builtin_define ( "__riscv_cmodel_medany" ) ; break ; } if ( TARGET_MIN_VLEN != 0 ) builtin_define_with_int_value ( "__riscv_v_min_vlen" , TARGET_MIN_VLEN ) ; if ( TARGET_VECTOR_ELEN_64 ) builtin_define_with_int_value ( "__riscv_v_elen" , 64 ) ; else if ( TARGET_VECTOR_ELEN_32 ) builtin_define_with_int_value ( "__riscv_v_elen" , 32 ) ; if ( TARGET_VECTOR_ELEN_FP_64 ) builtin_define_with_int_value ( "__riscv_v_elen_fp" , 64 ) ; else if ( TARGET_VECTOR_ELEN_FP_32 ) builtin_define_with_int_value ( "__riscv_v_elen_fp" , 32 ) ; else if ( TARGET_MIN_VLEN != 0 ) builtin_define_with_int_value ( "__riscv_v_elen_fp" , 0 ) ; if ( TARGET_MIN_VLEN ) { builtin_define ( "__riscv_vector" ) ; builtin_define_with_int_value ( "__riscv_v_intrinsic" , riscv_ext_version_value ( 0 , 11 ) ) ; } builtin_define_with_int_value ( "__riscv_arch_test" , 1 ) ; const riscv_subset_list * subset_list = riscv_current_subset_list ( ) ; if ( ! subset_list ) return ; size_t max_ext_len = 0 ; for ( const riscv_subset_t * subset = subset_list -> begin ( ) ; subset != subset_list -> end ( ) ; subset = subset -> next ) max_ext_len = MAX ( max_ext_len , subset -> name . length ( ) ) ; char * buf = ( char * ) alloca ( max_ext_len + 10 ) ; for ( const riscv_subset_t * subset = subset_list -> begin ( ) ; subset != subset_list -> end ( ) ; subset = subset -> next ) { int version_value = riscv_ext_version_value ( subset -> major_version , subset -> minor_version ) ; if ( ( subset -> name == "zicsr" || subset -> name == "zifencei" ) && version_value == 0 ) version_value = riscv_ext_version_value ( 2 , 0 ) ; sprintf ( buf , "__riscv_%s" , subset -> name . c_str ( ) ) ; builtin_define_with_int_value ( buf , version_value ) ; } } </s>


<s> bool RISCVRegisterInfo :: hasReservedSpillSlot ( const MachineFunction & MF , Register Reg , int & FrameIdx ) const { const auto * RVFI = MF . getInfo < RISCVMachineFunctionInfo > ( ) ; if ( ! RVFI -> useSaveRestoreLibCalls ( ) ) return false ; auto FII = FixedCSRFIMap . find ( Reg ) ; if ( FII == FixedCSRFIMap . end ( ) ) return false ; FrameIdx = FII -> second ; return true ; } </s>

Return true if target has reserved a spill slot in the stack frame of the given function for the specified register .


<s> static bool riscv_valid_offset_p ( rtx x , machine_mode mode ) { if ( ! const_arith_operand ( x , Pmode ) ) return false ; if ( GET_MODE_SIZE ( mode ) > UNITS_PER_WORD && ! SMALL_OPERAND ( INTVAL ( x ) + GET_MODE_SIZE ( mode ) - UNITS_PER_WORD ) ) return false ; return true ; } </s>

Return true if , for every base register BASE_REG , ( plus BASE_REG X ) can address a value of mode MODE .


<s> bool RISCVTargetLowering :: decomposeMulByConstant ( LLVMContext & Context , EVT VT , SDValue C ) const { if ( VT . isScalarInteger ( ) ) { if ( Subtarget . hasStdExtM ( ) && VT . getSizeInBits ( ) > Subtarget . getXLen ( ) ) return false ; if ( auto * ConstNode = dyn_cast < ConstantSDNode > ( C . getNode ( ) ) ) { const APInt & Imm = ConstNode -> getAPIntValue ( ) ; if ( ( Imm + 1 ) . isPowerOf2 ( ) || ( Imm - 1 ) . isPowerOf2 ( ) || ( 1 - Imm ) . isPowerOf2 ( ) || ( - 1 - Imm ) . isPowerOf2 ( ) ) return true ; if ( Subtarget . hasStdExtM ( ) && VT . getSizeInBits ( ) >= Subtarget . getXLen ( ) ) return false ; if ( ! Imm . isSignedIntN ( 12 ) && Imm . countTrailingZeros ( ) < 12 ) { APInt ImmS = Imm . ashr ( Imm . countTrailingZeros ( ) ) ; if ( ( ImmS + 1 ) . isPowerOf2 ( ) || ( ImmS - 1 ) . isPowerOf2 ( ) || ( 1 - ImmS ) . isPowerOf2 ( ) ) return true ; } } } return false ; } </s>

Return true if it is profitable to transform an integer multiplication-by-constant into simpler operations like shifts and adds .


"Don't know how to custom type legalize this operation!"

"READCYCLECOUNTER only has custom type legalization on riscv32"

ReplaceNodeResults - Replace the results of node with an illegal result type with new values built out of custom code .


"Can't load this register from stack slot"

Load the specified register of the given register class from the specified stack frame index .