diff options
| author | Richard-Qin-X <richard.qin.001@gmail.com> | 2026-08-07 22:06:28 +0800 |
|---|---|---|
| committer | Richard-Qin-X <richard.qin.001@gmail.com> | 2026-08-07 22:06:28 +0800 |
| commit | f99ef4322a7a2c09380fff61f88ab9440f05a92c (patch) | |
| tree | 69538d9ac3acb4a4a680dbce143f39c7b576035c /backend/include/rcc/CodeGen | |
| parent | 3e15bfd7b075209ec3b65d30d0611e060f6fbb77 (diff) | |
| download | rcc-project-f99ef4322a7a2c09380fff61f88ab9440f05a92c.tar.gz rcc-project-f99ef4322a7a2c09380fff61f88ab9440f05a92c.tar.xz | |
[CodeGen] Complete machine pass and ABI lowering infrastructure
Diffstat (limited to 'backend/include/rcc/CodeGen')
| -rw-r--r-- | backend/include/rcc/CodeGen/GenericOpcode.def | 336 | ||||
| -rw-r--r-- | backend/include/rcc/CodeGen/GenericOpcodes.h | 68 | ||||
| -rw-r--r-- | backend/include/rcc/CodeGen/MachineAnalyses.h | 244 | ||||
| -rw-r--r-- | backend/include/rcc/CodeGen/MachineIRBuilder.h | 10 | ||||
| -rw-r--r-- | backend/include/rcc/CodeGen/MachineIRTypes.h | 3 | ||||
| -rw-r--r-- | backend/include/rcc/CodeGen/MachinePass.h | 655 | ||||
| -rw-r--r-- | backend/include/rcc/CodeGen/TargetCallLowering.h | 404 |
7 files changed, 1720 insertions, 0 deletions
diff --git a/backend/include/rcc/CodeGen/GenericOpcode.def b/backend/include/rcc/CodeGen/GenericOpcode.def new file mode 100644 index 0000000..8caaf7b --- /dev/null +++ b/backend/include/rcc/CodeGen/GenericOpcode.def @@ -0,0 +1,336 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +// This file is intentionally included multiple times. Define +// RCC_CORE_OPCODE and RCC_GENERIC_OPCODE before including it. + +RCC_CORE_OPCODE(PHI) +RCC_CORE_OPCODE(INLINEASM) +RCC_CORE_OPCODE(INLINEASM_BR) +RCC_CORE_OPCODE(CFI_INSTRUCTION) +RCC_CORE_OPCODE(EH_LABEL) +RCC_CORE_OPCODE(GC_LABEL) +RCC_CORE_OPCODE(ANNOTATION_LABEL) +RCC_CORE_OPCODE(KILL) +RCC_CORE_OPCODE(EXTRACT_SUBREG) +RCC_CORE_OPCODE(INSERT_SUBREG) +RCC_CORE_OPCODE(IMPLICIT_DEF) +RCC_CORE_OPCODE(INIT_UNDEF) +RCC_CORE_OPCODE(SUBREG_TO_REG) +RCC_CORE_OPCODE(COPY_TO_REGCLASS) +RCC_CORE_OPCODE(DBG_VALUE) +RCC_CORE_OPCODE(DBG_VALUE_LIST) +RCC_CORE_OPCODE(DBG_INSTR_REF) +RCC_CORE_OPCODE(DBG_PHI) +RCC_CORE_OPCODE(DBG_LABEL) +RCC_CORE_OPCODE(REG_SEQUENCE) +RCC_CORE_OPCODE(COPY) +RCC_CORE_OPCODE(COPY_LANEMASK) +RCC_CORE_OPCODE(BUNDLE) +RCC_CORE_OPCODE(LIFETIME_START) +RCC_CORE_OPCODE(LIFETIME_END) +RCC_CORE_OPCODE(PSEUDO_PROBE) +RCC_CORE_OPCODE(ARITH_FENCE) +RCC_CORE_OPCODE(STACKMAP) +RCC_CORE_OPCODE(FENTRY_CALL) +RCC_CORE_OPCODE(PATCHPOINT) +RCC_CORE_OPCODE(LOAD_STACK_GUARD) +RCC_CORE_OPCODE(PREALLOCATED_SETUP) +RCC_CORE_OPCODE(PREALLOCATED_ARG) +RCC_CORE_OPCODE(STATEPOINT) +RCC_CORE_OPCODE(LOCAL_ESCAPE) +RCC_CORE_OPCODE(FAULTING_OP) +RCC_CORE_OPCODE(PATCHABLE_OP) +RCC_CORE_OPCODE(PATCHABLE_FUNCTION_ENTER) +RCC_CORE_OPCODE(PATCHABLE_RET) +RCC_CORE_OPCODE(PATCHABLE_FUNCTION_EXIT) +RCC_CORE_OPCODE(PATCHABLE_TAIL_CALL) +RCC_CORE_OPCODE(PATCHABLE_EVENT_CALL) +RCC_CORE_OPCODE(PATCHABLE_TYPED_EVENT_CALL) +RCC_CORE_OPCODE(ICALL_BRANCH_FUNNEL) +RCC_CORE_OPCODE(FAKE_USE) +RCC_CORE_OPCODE(MEMBARRIER) +RCC_CORE_OPCODE(JUMP_TABLE_DEBUG_INFO) +RCC_CORE_OPCODE(RELOC_NONE) +RCC_CORE_OPCODE(CONVERGENCECTRL_ENTRY) +RCC_CORE_OPCODE(CONVERGENCECTRL_ANCHOR) +RCC_CORE_OPCODE(CONVERGENCECTRL_LOOP) +RCC_CORE_OPCODE(CONVERGENCECTRL_GLUE) + +RCC_GENERIC_OPCODE(G_ASSERT_SEXT) +RCC_GENERIC_OPCODE(G_ASSERT_ZEXT) +RCC_GENERIC_OPCODE(G_ASSERT_ALIGN) +RCC_GENERIC_OPCODE(G_ADD) +RCC_GENERIC_OPCODE(G_SUB) +RCC_GENERIC_OPCODE(G_MUL) +RCC_GENERIC_OPCODE(G_SDIV) +RCC_GENERIC_OPCODE(G_UDIV) +RCC_GENERIC_OPCODE(G_SREM) +RCC_GENERIC_OPCODE(G_UREM) +RCC_GENERIC_OPCODE(G_SDIVREM) +RCC_GENERIC_OPCODE(G_UDIVREM) +RCC_GENERIC_OPCODE(G_AND) +RCC_GENERIC_OPCODE(G_OR) +RCC_GENERIC_OPCODE(G_XOR) +RCC_GENERIC_OPCODE(G_ABDS) +RCC_GENERIC_OPCODE(G_ABDU) +RCC_GENERIC_OPCODE(G_UAVGFLOOR) +RCC_GENERIC_OPCODE(G_UAVGCEIL) +RCC_GENERIC_OPCODE(G_SAVGFLOOR) +RCC_GENERIC_OPCODE(G_SAVGCEIL) +RCC_GENERIC_OPCODE(G_IMPLICIT_DEF) +RCC_GENERIC_OPCODE(G_PHI) +RCC_GENERIC_OPCODE(G_FRAME_INDEX) +RCC_GENERIC_OPCODE(G_GLOBAL_VALUE) +RCC_GENERIC_OPCODE(G_PTRAUTH_GLOBAL_VALUE) +RCC_GENERIC_OPCODE(G_CONSTANT_POOL) +RCC_GENERIC_OPCODE(G_EXTRACT) +RCC_GENERIC_OPCODE(G_UNMERGE_VALUES) +RCC_GENERIC_OPCODE(G_INSERT) +RCC_GENERIC_OPCODE(G_MERGE_VALUES) +RCC_GENERIC_OPCODE(G_BUILD_VECTOR) +RCC_GENERIC_OPCODE(G_BUILD_VECTOR_TRUNC) +RCC_GENERIC_OPCODE(G_CONCAT_VECTORS) +RCC_GENERIC_OPCODE(G_PTRTOINT) +RCC_GENERIC_OPCODE(G_INTTOPTR) +RCC_GENERIC_OPCODE(G_BITCAST) +RCC_GENERIC_OPCODE(G_FREEZE) +RCC_GENERIC_OPCODE(G_CONSTANT_FOLD_BARRIER) +RCC_GENERIC_OPCODE(G_INTRINSIC_FPTRUNC_ROUND) +RCC_GENERIC_OPCODE(G_INTRINSIC_TRUNC) +RCC_GENERIC_OPCODE(G_INTRINSIC_ROUND) +RCC_GENERIC_OPCODE(G_INTRINSIC_LRINT) +RCC_GENERIC_OPCODE(G_INTRINSIC_LLRINT) +RCC_GENERIC_OPCODE(G_INTRINSIC_ROUNDEVEN) +RCC_GENERIC_OPCODE(G_READCYCLECOUNTER) +RCC_GENERIC_OPCODE(G_READSTEADYCOUNTER) +RCC_GENERIC_OPCODE(G_LOAD) +RCC_GENERIC_OPCODE(G_SEXTLOAD) +RCC_GENERIC_OPCODE(G_ZEXTLOAD) +RCC_GENERIC_OPCODE(G_FPEXTLOAD) +RCC_GENERIC_OPCODE(G_INDEXED_LOAD) +RCC_GENERIC_OPCODE(G_INDEXED_SEXTLOAD) +RCC_GENERIC_OPCODE(G_INDEXED_ZEXTLOAD) +RCC_GENERIC_OPCODE(G_STORE) +RCC_GENERIC_OPCODE(G_FPTRUNCSTORE) +RCC_GENERIC_OPCODE(G_INDEXED_STORE) +RCC_GENERIC_OPCODE(G_ATOMIC_CMPXCHG_WITH_SUCCESS) +RCC_GENERIC_OPCODE(G_ATOMIC_CMPXCHG) +RCC_GENERIC_OPCODE(G_ATOMICRMW_XCHG) +RCC_GENERIC_OPCODE(G_ATOMICRMW_ADD) +RCC_GENERIC_OPCODE(G_ATOMICRMW_SUB) +RCC_GENERIC_OPCODE(G_ATOMICRMW_AND) +RCC_GENERIC_OPCODE(G_ATOMICRMW_NAND) +RCC_GENERIC_OPCODE(G_ATOMICRMW_OR) +RCC_GENERIC_OPCODE(G_ATOMICRMW_XOR) +RCC_GENERIC_OPCODE(G_ATOMICRMW_MAX) +RCC_GENERIC_OPCODE(G_ATOMICRMW_MIN) +RCC_GENERIC_OPCODE(G_ATOMICRMW_UMAX) +RCC_GENERIC_OPCODE(G_ATOMICRMW_UMIN) +RCC_GENERIC_OPCODE(G_ATOMICRMW_FADD) +RCC_GENERIC_OPCODE(G_ATOMICRMW_FSUB) +RCC_GENERIC_OPCODE(G_ATOMICRMW_FMAX) +RCC_GENERIC_OPCODE(G_ATOMICRMW_FMIN) +RCC_GENERIC_OPCODE(G_ATOMICRMW_FMAXIMUM) +RCC_GENERIC_OPCODE(G_ATOMICRMW_FMINIMUM) +RCC_GENERIC_OPCODE(G_ATOMICRMW_FMAXIMUMNUM) +RCC_GENERIC_OPCODE(G_ATOMICRMW_FMINIMUMNUM) +RCC_GENERIC_OPCODE(G_ATOMICRMW_UINC_WRAP) +RCC_GENERIC_OPCODE(G_ATOMICRMW_UDEC_WRAP) +RCC_GENERIC_OPCODE(G_ATOMICRMW_USUB_COND) +RCC_GENERIC_OPCODE(G_ATOMICRMW_USUB_SAT) +RCC_GENERIC_OPCODE(G_FENCE) +RCC_GENERIC_OPCODE(G_PREFETCH) +RCC_GENERIC_OPCODE(G_BRCOND) +RCC_GENERIC_OPCODE(G_BRINDIRECT) +RCC_GENERIC_OPCODE(G_INVOKE_REGION_START) +RCC_GENERIC_OPCODE(G_INTRINSIC) +RCC_GENERIC_OPCODE(G_INTRINSIC_W_SIDE_EFFECTS) +RCC_GENERIC_OPCODE(G_INTRINSIC_CONVERGENT) +RCC_GENERIC_OPCODE(G_INTRINSIC_CONVERGENT_W_SIDE_EFFECTS) +RCC_GENERIC_OPCODE(G_ANYEXT) +RCC_GENERIC_OPCODE(G_TRUNC) +RCC_GENERIC_OPCODE(G_TRUNC_SSAT_S) +RCC_GENERIC_OPCODE(G_TRUNC_SSAT_U) +RCC_GENERIC_OPCODE(G_TRUNC_USAT_U) +RCC_GENERIC_OPCODE(G_CONSTANT) +RCC_GENERIC_OPCODE(G_FCONSTANT) +RCC_GENERIC_OPCODE(G_VASTART) +RCC_GENERIC_OPCODE(G_VAARG) +RCC_GENERIC_OPCODE(G_SEXT) +RCC_GENERIC_OPCODE(G_SEXT_INREG) +RCC_GENERIC_OPCODE(G_ZEXT) +RCC_GENERIC_OPCODE(G_SHL) +RCC_GENERIC_OPCODE(G_LSHR) +RCC_GENERIC_OPCODE(G_ASHR) +RCC_GENERIC_OPCODE(G_FSHL) +RCC_GENERIC_OPCODE(G_FSHR) +RCC_GENERIC_OPCODE(G_ROTR) +RCC_GENERIC_OPCODE(G_ROTL) +RCC_GENERIC_OPCODE(G_ICMP) +RCC_GENERIC_OPCODE(G_FCMP) +RCC_GENERIC_OPCODE(G_SCMP) +RCC_GENERIC_OPCODE(G_UCMP) +RCC_GENERIC_OPCODE(G_SELECT) +RCC_GENERIC_OPCODE(G_UADDO) +RCC_GENERIC_OPCODE(G_UADDE) +RCC_GENERIC_OPCODE(G_USUBO) +RCC_GENERIC_OPCODE(G_USUBE) +RCC_GENERIC_OPCODE(G_SADDO) +RCC_GENERIC_OPCODE(G_SADDE) +RCC_GENERIC_OPCODE(G_SSUBO) +RCC_GENERIC_OPCODE(G_SSUBE) +RCC_GENERIC_OPCODE(G_UMULO) +RCC_GENERIC_OPCODE(G_SMULO) +RCC_GENERIC_OPCODE(G_UMULH) +RCC_GENERIC_OPCODE(G_SMULH) +RCC_GENERIC_OPCODE(G_UADDSAT) +RCC_GENERIC_OPCODE(G_SADDSAT) +RCC_GENERIC_OPCODE(G_USUBSAT) +RCC_GENERIC_OPCODE(G_SSUBSAT) +RCC_GENERIC_OPCODE(G_USHLSAT) +RCC_GENERIC_OPCODE(G_SSHLSAT) +RCC_GENERIC_OPCODE(G_SMULFIX) +RCC_GENERIC_OPCODE(G_UMULFIX) +RCC_GENERIC_OPCODE(G_SMULFIXSAT) +RCC_GENERIC_OPCODE(G_UMULFIXSAT) +RCC_GENERIC_OPCODE(G_SDIVFIX) +RCC_GENERIC_OPCODE(G_UDIVFIX) +RCC_GENERIC_OPCODE(G_SDIVFIXSAT) +RCC_GENERIC_OPCODE(G_UDIVFIXSAT) +RCC_GENERIC_OPCODE(G_FADD) +RCC_GENERIC_OPCODE(G_FSUB) +RCC_GENERIC_OPCODE(G_FMUL) +RCC_GENERIC_OPCODE(G_FMA) +RCC_GENERIC_OPCODE(G_FMAD) +RCC_GENERIC_OPCODE(G_FDIV) +RCC_GENERIC_OPCODE(G_FREM) +RCC_GENERIC_OPCODE(G_FMODF) +RCC_GENERIC_OPCODE(G_FPOW) +RCC_GENERIC_OPCODE(G_FPOWI) +RCC_GENERIC_OPCODE(G_FEXP) +RCC_GENERIC_OPCODE(G_FEXP2) +RCC_GENERIC_OPCODE(G_FEXP10) +RCC_GENERIC_OPCODE(G_FLOG) +RCC_GENERIC_OPCODE(G_FLOG2) +RCC_GENERIC_OPCODE(G_FLOG10) +RCC_GENERIC_OPCODE(G_FLDEXP) +RCC_GENERIC_OPCODE(G_FFREXP) +RCC_GENERIC_OPCODE(G_FNEG) +RCC_GENERIC_OPCODE(G_FPEXT) +RCC_GENERIC_OPCODE(G_FPTRUNC) +RCC_GENERIC_OPCODE(G_FPTOSI) +RCC_GENERIC_OPCODE(G_FPTOUI) +RCC_GENERIC_OPCODE(G_SITOFP) +RCC_GENERIC_OPCODE(G_UITOFP) +RCC_GENERIC_OPCODE(G_FPTOSI_SAT) +RCC_GENERIC_OPCODE(G_FPTOUI_SAT) +RCC_GENERIC_OPCODE(G_FABS) +RCC_GENERIC_OPCODE(G_FCOPYSIGN) +RCC_GENERIC_OPCODE(G_IS_FPCLASS) +RCC_GENERIC_OPCODE(G_FCANONICALIZE) +RCC_GENERIC_OPCODE(G_FMINNUM) +RCC_GENERIC_OPCODE(G_FMAXNUM) +RCC_GENERIC_OPCODE(G_FMINNUM_IEEE) +RCC_GENERIC_OPCODE(G_FMAXNUM_IEEE) +RCC_GENERIC_OPCODE(G_FMINIMUM) +RCC_GENERIC_OPCODE(G_FMAXIMUM) +RCC_GENERIC_OPCODE(G_FMINIMUMNUM) +RCC_GENERIC_OPCODE(G_FMAXIMUMNUM) +RCC_GENERIC_OPCODE(G_GET_FPENV) +RCC_GENERIC_OPCODE(G_SET_FPENV) +RCC_GENERIC_OPCODE(G_RESET_FPENV) +RCC_GENERIC_OPCODE(G_GET_FPMODE) +RCC_GENERIC_OPCODE(G_SET_FPMODE) +RCC_GENERIC_OPCODE(G_RESET_FPMODE) +RCC_GENERIC_OPCODE(G_GET_ROUNDING) +RCC_GENERIC_OPCODE(G_SET_ROUNDING) +RCC_GENERIC_OPCODE(G_PTR_ADD) +RCC_GENERIC_OPCODE(G_PTRMASK) +RCC_GENERIC_OPCODE(G_SMIN) +RCC_GENERIC_OPCODE(G_SMAX) +RCC_GENERIC_OPCODE(G_UMIN) +RCC_GENERIC_OPCODE(G_UMAX) +RCC_GENERIC_OPCODE(G_ABS) +RCC_GENERIC_OPCODE(G_LROUND) +RCC_GENERIC_OPCODE(G_LLROUND) +RCC_GENERIC_OPCODE(G_BR) +RCC_GENERIC_OPCODE(G_BRJT) +RCC_GENERIC_OPCODE(G_VSCALE) +RCC_GENERIC_OPCODE(G_INSERT_SUBVECTOR) +RCC_GENERIC_OPCODE(G_EXTRACT_SUBVECTOR) +RCC_GENERIC_OPCODE(G_INSERT_VECTOR_ELT) +RCC_GENERIC_OPCODE(G_EXTRACT_VECTOR_ELT) +RCC_GENERIC_OPCODE(G_SHUFFLE_VECTOR) +RCC_GENERIC_OPCODE(G_SPLAT_VECTOR) +RCC_GENERIC_OPCODE(G_STEP_VECTOR) +RCC_GENERIC_OPCODE(G_VECTOR_COMPRESS) +RCC_GENERIC_OPCODE(G_CTTZ) +RCC_GENERIC_OPCODE(G_CTTZ_ZERO_POISON) +RCC_GENERIC_OPCODE(G_CTLZ) +RCC_GENERIC_OPCODE(G_CTLZ_ZERO_POISON) +RCC_GENERIC_OPCODE(G_CTLS) +RCC_GENERIC_OPCODE(G_CTPOP) +RCC_GENERIC_OPCODE(G_BSWAP) +RCC_GENERIC_OPCODE(G_BITREVERSE) +RCC_GENERIC_OPCODE(G_CLMUL) +RCC_GENERIC_OPCODE(G_FCEIL) +RCC_GENERIC_OPCODE(G_FCOS) +RCC_GENERIC_OPCODE(G_FSIN) +RCC_GENERIC_OPCODE(G_FSINCOS) +RCC_GENERIC_OPCODE(G_FTAN) +RCC_GENERIC_OPCODE(G_FACOS) +RCC_GENERIC_OPCODE(G_FASIN) +RCC_GENERIC_OPCODE(G_FATAN) +RCC_GENERIC_OPCODE(G_FATAN2) +RCC_GENERIC_OPCODE(G_FCOSH) +RCC_GENERIC_OPCODE(G_FSINH) +RCC_GENERIC_OPCODE(G_FTANH) +RCC_GENERIC_OPCODE(G_FSQRT) +RCC_GENERIC_OPCODE(G_FFLOOR) +RCC_GENERIC_OPCODE(G_FRINT) +RCC_GENERIC_OPCODE(G_FNEARBYINT) +RCC_GENERIC_OPCODE(G_ADDRSPACE_CAST) +RCC_GENERIC_OPCODE(G_BLOCK_ADDR) +RCC_GENERIC_OPCODE(G_JUMP_TABLE) +RCC_GENERIC_OPCODE(G_DYN_STACKALLOC) +RCC_GENERIC_OPCODE(G_STACKSAVE) +RCC_GENERIC_OPCODE(G_STACKRESTORE) +RCC_GENERIC_OPCODE(G_STRICT_FADD) +RCC_GENERIC_OPCODE(G_STRICT_FSUB) +RCC_GENERIC_OPCODE(G_STRICT_FMUL) +RCC_GENERIC_OPCODE(G_STRICT_FDIV) +RCC_GENERIC_OPCODE(G_STRICT_FREM) +RCC_GENERIC_OPCODE(G_STRICT_FMA) +RCC_GENERIC_OPCODE(G_STRICT_FSQRT) +RCC_GENERIC_OPCODE(G_STRICT_FLDEXP) +RCC_GENERIC_OPCODE(G_STRICT_FCMP) +RCC_GENERIC_OPCODE(G_STRICT_FCMPS) +RCC_GENERIC_OPCODE(G_READ_REGISTER) +RCC_GENERIC_OPCODE(G_WRITE_REGISTER) +RCC_GENERIC_OPCODE(G_MEMCPY) +RCC_GENERIC_OPCODE(G_MEMCPY_INLINE) +RCC_GENERIC_OPCODE(G_MEMMOVE) +RCC_GENERIC_OPCODE(G_MEMSET) +RCC_GENERIC_OPCODE(G_BZERO) +RCC_GENERIC_OPCODE(G_TRAP) +RCC_GENERIC_OPCODE(G_DEBUGTRAP) +RCC_GENERIC_OPCODE(G_UBSANTRAP) +RCC_GENERIC_OPCODE(G_VECREDUCE_SEQ_FADD) +RCC_GENERIC_OPCODE(G_VECREDUCE_SEQ_FMUL) +RCC_GENERIC_OPCODE(G_VECREDUCE_FADD) +RCC_GENERIC_OPCODE(G_VECREDUCE_FMUL) +RCC_GENERIC_OPCODE(G_VECREDUCE_FMAX) +RCC_GENERIC_OPCODE(G_VECREDUCE_FMIN) +RCC_GENERIC_OPCODE(G_VECREDUCE_FMAXIMUM) +RCC_GENERIC_OPCODE(G_VECREDUCE_FMINIMUM) +RCC_GENERIC_OPCODE(G_VECREDUCE_ADD) +RCC_GENERIC_OPCODE(G_VECREDUCE_MUL) +RCC_GENERIC_OPCODE(G_VECREDUCE_AND) +RCC_GENERIC_OPCODE(G_VECREDUCE_OR) +RCC_GENERIC_OPCODE(G_VECREDUCE_XOR) +RCC_GENERIC_OPCODE(G_VECREDUCE_SMAX) +RCC_GENERIC_OPCODE(G_VECREDUCE_SMIN) +RCC_GENERIC_OPCODE(G_VECREDUCE_UMAX) +RCC_GENERIC_OPCODE(G_VECREDUCE_UMIN) +RCC_GENERIC_OPCODE(G_SBFX) +RCC_GENERIC_OPCODE(G_UBFX) diff --git a/backend/include/rcc/CodeGen/GenericOpcodes.h b/backend/include/rcc/CodeGen/GenericOpcodes.h new file mode 100644 index 0000000..5a46e21 --- /dev/null +++ b/backend/include/rcc/CodeGen/GenericOpcodes.h @@ -0,0 +1,68 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef RCC_CODEGEN_GENERICOPCODES_H +#define RCC_CODEGEN_GENERICOPCODES_H + +#include "rcc/CodeGen/InstructionDescriptor.h" + +#include <cstdint> +#include <span> +#include <string_view> +#include <vector> + +namespace rcc { + +// Target-independent values are build-local. Target tables start at 1024 and +// are appended to this set when a target description is constructed. +enum class GenericOpcode : std::uint32_t { + Invalid, +#define RCC_CORE_OPCODE(Name) Name, +#define RCC_GENERIC_OPCODE(Name) +#include "rcc/CodeGen/GenericOpcode.def" +#undef RCC_GENERIC_OPCODE +#undef RCC_CORE_OPCODE + CORE_PSEUDO_END, + +#define RCC_CORE_OPCODE(Name) +#define RCC_GENERIC_OPCODE(Name) Name, +#include "rcc/CodeGen/GenericOpcode.def" +#undef RCC_GENERIC_OPCODE +#undef RCC_CORE_OPCODE + G_GENERIC_END, +}; + +[[nodiscard]] constexpr Opcode opcode(GenericOpcode Generic) noexcept { + return Opcode::fromValue(static_cast<std::uint32_t>(Generic)); +} + +[[nodiscard]] constexpr bool isGenericOpcode(Opcode Value) noexcept { + return Value.value() >= static_cast<std::uint32_t>(GenericOpcode::G_ASSERT_SEXT) && + Value.value() < static_cast<std::uint32_t>(GenericOpcode::G_GENERIC_END); +} + +[[nodiscard]] constexpr bool isCorePseudoOpcode(Opcode Value) noexcept { + return Value.value() >= static_cast<std::uint32_t>(GenericOpcode::PHI) && + Value.value() < static_cast<std::uint32_t>(GenericOpcode::CORE_PSEUDO_END); +} + +inline constexpr std::size_t CorePseudoOpcodeCount = + static_cast<std::size_t>(GenericOpcode::CORE_PSEUDO_END) - + static_cast<std::size_t>(GenericOpcode::PHI); + +inline constexpr std::size_t GenericOpcodeCount = + static_cast<std::size_t>(GenericOpcode::G_GENERIC_END) - + static_cast<std::size_t>(GenericOpcode::G_ASSERT_SEXT); + +[[nodiscard]] std::string_view getGenericOpcodeName(GenericOpcode OpcodeValue) noexcept; + +[[nodiscard]] std::span<const InstructionDescriptor> genericInstructionDescriptors() noexcept; + +[[nodiscard]] std::span<const ImmediatePredicate> genericImmediatePredicates() noexcept; + +[[nodiscard]] Expected<void> +appendGenericInstructionInfo(std::vector<InstructionDescriptor> &Descriptors, + std::vector<ImmediatePredicate> &Predicates); + +} // namespace rcc + +#endif // RCC_CODEGEN_GENERICOPCODES_H diff --git a/backend/include/rcc/CodeGen/MachineAnalyses.h b/backend/include/rcc/CodeGen/MachineAnalyses.h new file mode 100644 index 0000000..eda550d --- /dev/null +++ b/backend/include/rcc/CodeGen/MachineAnalyses.h @@ -0,0 +1,244 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef RCC_CODEGEN_MACHINEANALYSES_H +#define RCC_CODEGEN_MACHINEANALYSES_H + +#include "rcc/CodeGen/MachineBasicBlock.h" +#include "rcc/CodeGen/MachineIRTypes.h" +#include "rcc/CodeGen/MachinePass.h" +#include "rcc/CodeGen/StableID.h" +#include "rcc/Support/Error.h" + +#include <cstddef> +#include <cstdint> +#include <span> +#include <string_view> +#include <unordered_map> +#include <unordered_set> +#include <vector> + +namespace rcc { + +class MachineBasicBlock; +class MachineFunction; +class MachineInstr; +class MachineMemOperand; +class TargetDescription; + +class MachineDominatorTreeAnalysis final { +public: + class Result final { + public: + [[nodiscard]] bool isReachable(const MachineBasicBlock &Block) const noexcept; + [[nodiscard]] bool dominates(const MachineBasicBlock &Dominator, + const MachineBasicBlock &Block) const noexcept; + [[nodiscard]] bool dominates(const MachineInstr &Dominator, + const MachineInstr &Instruction) const noexcept; + [[nodiscard]] const MachineBasicBlock * + immediateDominator(const MachineBasicBlock &Block) const noexcept; + [[nodiscard]] const MachineBasicBlock * + nearestCommonDominator(const MachineBasicBlock &Left, + const MachineBasicBlock &Right) const noexcept; + [[nodiscard]] std::span<MachineBasicBlock *const> unreachableBlocks() const noexcept { + return UnreachableBlocks; + } + + [[nodiscard]] Expected<void> updateAfterCFGChange(MachineFunction &Function); + + private: + [[nodiscard]] Expected<void> build(MachineFunction &Function); + + std::vector<MachineBasicBlock *> Blocks; + std::unordered_map<const MachineBasicBlock *, std::size_t> BlockToIndex; + std::vector<std::vector<bool>> Dominators; + std::vector<const MachineBasicBlock *> ImmediateDominators; + std::vector<bool> Reachable; + std::vector<MachineBasicBlock *> UnreachableBlocks; + + friend class MachineDominatorTreeAnalysis; + }; + + [[nodiscard]] static constexpr std::string_view name() noexcept { + return "MachineDominatorTree"; + } + + [[nodiscard]] static Expected<Result> + run(MachineFunction &Function, const TargetDescription &Target, MachineAnalysisManager &Analyses); +}; + +struct MachineLoop final { + MachineBasicBlock *Header = nullptr; + std::vector<MachineBasicBlock *> Blocks; + std::vector<MachineBasicBlock *> Latches; + std::size_t Parent = static_cast<std::size_t>(-1); + std::vector<std::size_t> Children; + std::uint32_t Depth = 1; +}; + +struct IrreducibleMachineRegion final { + std::vector<MachineBasicBlock *> Blocks; + std::vector<MachineBasicBlock *> Entries; +}; + +class MachineLoopAnalysis final { +public: + class Result final { + public: + [[nodiscard]] std::span<const MachineLoop> loops() const noexcept { + return Loops; + } + [[nodiscard]] std::span<const IrreducibleMachineRegion> irreducibleRegions() const noexcept { + return IrreducibleRegions; + } + [[nodiscard]] const MachineLoop *loopFor(const MachineBasicBlock &Block) const noexcept; + [[nodiscard]] std::uint32_t loopDepth(const MachineBasicBlock &Block) const noexcept; + [[nodiscard]] bool isIrreducible(const MachineBasicBlock &Block) const noexcept; + + private: + std::vector<MachineLoop> Loops; + std::vector<IrreducibleMachineRegion> IrreducibleRegions; + std::unordered_map<const MachineBasicBlock *, std::size_t> InnermostLoop; + std::unordered_set<const MachineBasicBlock *> IrreducibleBlocks; + + friend class MachineLoopAnalysis; + }; + + [[nodiscard]] static constexpr std::string_view name() noexcept { + return "MachineLoopInfo"; + } + + [[nodiscard]] static Expected<Result> + run(MachineFunction &Function, const TargetDescription &Target, MachineAnalysisManager &Analyses); +}; + +class MachineBranchProbabilityAnalysis final { +public: + class Result final { + public: + [[nodiscard]] BranchProbability probability(const MachineBasicBlock &From, + const MachineBasicBlock &To) const noexcept; + [[nodiscard]] std::span<const MachineSuccessor> + successors(const MachineBasicBlock &Block) const noexcept; + + private: + std::unordered_map<const MachineBasicBlock *, std::vector<MachineSuccessor>> Probabilities; + + friend class MachineBranchProbabilityAnalysis; + }; + + [[nodiscard]] static constexpr std::string_view name() noexcept { + return "MachineBranchProbability"; + } + + [[nodiscard]] static Expected<Result> + run(MachineFunction &Function, const TargetDescription &Target, MachineAnalysisManager &Analyses); +}; + +class MachineBlockFrequencyAnalysis final { +public: + static constexpr std::uint64_t EntryFrequency = std::uint64_t{1} << 32U; + + class Result final { + public: + [[nodiscard]] std::uint64_t frequency(const MachineBasicBlock &Block) const noexcept; + + private: + std::unordered_map<const MachineBasicBlock *, std::uint64_t> Frequencies; + + friend class MachineBlockFrequencyAnalysis; + }; + + [[nodiscard]] static constexpr std::string_view name() noexcept { + return "MachineBlockFrequency"; + } + + [[nodiscard]] static Expected<Result> + run(MachineFunction &Function, const TargetDescription &Target, MachineAnalysisManager &Analyses); +}; + +enum class MachineAliasResult : std::uint8_t { + NoAlias, + MayAlias, + PartialAlias, + MustAlias, +}; + +class MachineAliasAnalysis final { +public: + class Result final { + public: + [[nodiscard]] MachineAliasResult alias(const MachineMemOperand &Left, + const MachineMemOperand &Right) const noexcept; + }; + + [[nodiscard]] static constexpr std::string_view name() noexcept { + return "MachineAliasAnalysis"; + } + + [[nodiscard]] static Expected<Result> + run(MachineFunction &Function, const TargetDescription &Target, MachineAnalysisManager &Analyses); +}; + +enum class MachineMemoryDependencyKind : std::uint8_t { + Flow, + Anti, + Output, + Ordered, +}; + +struct MachineMemoryDependency final { + MachineInstrStableID Source; + MachineInstrStableID Destination; + MachineMemoryDependencyKind Kind = MachineMemoryDependencyKind::Ordered; +}; + +struct MachineMemoryDependenceRegion final { + const MachineBasicBlock *Block = nullptr; + std::vector<MachineInstrStableID> Instructions; +}; + +class MachineMemoryDependenceAnalysis final { +public: + class Result final { + public: + [[nodiscard]] std::span<const MachineMemoryDependenceRegion> regions() const noexcept { + return Regions; + } + [[nodiscard]] const MachineMemoryDependenceRegion * + regionFor(const MachineBasicBlock &Block) const noexcept; + [[nodiscard]] std::span<const MachineMemoryDependency> + dependencies(const MachineBasicBlock &Block) const noexcept; + [[nodiscard]] std::span<const MachineMemoryDependency> + dependencies(const MachineInstr &Instruction) const noexcept; + [[nodiscard]] std::span<const MachineMemoryDependency> allDependencies() const noexcept { + return Dependencies; + } + + private: + struct Range final { + std::size_t Begin = 0; + std::size_t Size = 0; + }; + + std::vector<MachineMemoryDependency> Dependencies; + std::vector<MachineMemoryDependenceRegion> Regions; + std::unordered_map<const MachineBasicBlock *, std::size_t> BlockToRegion; + std::unordered_map<const MachineBasicBlock *, Range> BlockRanges; + std::unordered_map<MachineInstrStableID, Range> DestinationRanges; + + friend class MachineMemoryDependenceAnalysis; + }; + + [[nodiscard]] static constexpr std::string_view name() noexcept { + return "MachineMemoryDependence"; + } + + [[nodiscard]] static Expected<Result> + run(MachineFunction &Function, const TargetDescription &Target, MachineAnalysisManager &Analyses); +}; + +[[nodiscard]] Expected<void> registerStage8MachineAnalyses(MachineAnalysisManager &Analyses); + +} // namespace rcc + +#endif // RCC_CODEGEN_MACHINEANALYSES_H diff --git a/backend/include/rcc/CodeGen/MachineIRBuilder.h b/backend/include/rcc/CodeGen/MachineIRBuilder.h index 2a5979b..2524c7a 100644 --- a/backend/include/rcc/CodeGen/MachineIRBuilder.h +++ b/backend/include/rcc/CodeGen/MachineIRBuilder.h @@ -161,6 +161,16 @@ public: return *Function; } + [[nodiscard]] const TargetDescription &target() const noexcept { + return *Target; + } + + [[nodiscard]] MachineBasicBlock *insertionBlock() const noexcept { + return InsertBlock; + } + + [[nodiscard]] Expected<void> verifyInsertPoint() const; + [[nodiscard]] Expected<void> setInsertPoint(MachineBasicBlock &Block); [[nodiscard]] Expected<void> setInsertPointBefore(MachineInstr &Instruction); [[nodiscard]] Expected<void> setInsertPointAfter(MachineInstr &Instruction); diff --git a/backend/include/rcc/CodeGen/MachineIRTypes.h b/backend/include/rcc/CodeGen/MachineIRTypes.h index f7095cc..ea65eff 100644 --- a/backend/include/rcc/CodeGen/MachineIRTypes.h +++ b/backend/include/rcc/CodeGen/MachineIRTypes.h @@ -61,6 +61,7 @@ struct OriginIDTag; struct TargetConstantTypeIDTag; struct TargetFunctionStateTypeIDTag; struct TargetRelocationKindIDTag; +struct CallingConventionIDTag; } // namespace detail @@ -86,6 +87,7 @@ using OriginID = MachineIndex<detail::OriginIDTag, std::uint64_t>; using TargetConstantTypeID = MachineIndex<detail::TargetConstantTypeIDTag, std::uint64_t>; using TargetFunctionStateTypeID = MachineIndex<detail::TargetFunctionStateTypeIDTag, std::uint64_t>; using TargetRelocationKindID = MachineIndex<detail::TargetRelocationKindIDTag>; +using CallingConventionID = MachineIndex<detail::CallingConventionIDTag>; class Alignment final { public: @@ -298,6 +300,7 @@ struct SourceLocation final { static_assert(sizeof(Opcode) == sizeof(std::uint32_t)); static_assert(sizeof(Alignment) == sizeof(std::uint64_t)); static_assert(sizeof(FrameIndex) == sizeof(std::uint32_t)); +static_assert(sizeof(CallingConventionID) == sizeof(std::uint32_t)); static_assert(sizeof(MemoryAliasSourceID) == sizeof(std::uint64_t)); static_assert(std::is_trivially_copyable_v<Opcode>); static_assert(std::is_trivially_copyable_v<FrameIndex>); diff --git a/backend/include/rcc/CodeGen/MachinePass.h b/backend/include/rcc/CodeGen/MachinePass.h new file mode 100644 index 0000000..66e3b6b --- /dev/null +++ b/backend/include/rcc/CodeGen/MachinePass.h @@ -0,0 +1,655 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef RCC_CODEGEN_MACHINEPASS_H +#define RCC_CODEGEN_MACHINEPASS_H + +#include "rcc/CodeGen/InstructionDescriptor.h" +#include "rcc/CodeGen/MachineFunctionProperties.h" +#include "rcc/Support/Error.h" + +#include <concepts> +#include <cstddef> +#include <cstdint> +#include <functional> +#include <initializer_list> +#include <memory> +#include <mutex> +#include <optional> +#include <span> +#include <string> +#include <string_view> +#include <unordered_map> +#include <unordered_set> +#include <utility> +#include <vector> + +namespace rcc { + +class CompilationUnit; +class MachineFunction; +class MachineVerifier; +class TargetDescription; + +using AnalysisID = const void *; + +enum class MachinePassChange : std::uint32_t { + None = 0, + Instructions = 1U << 0U, + Operands = 1U << 1U, + Registers = 1U << 2U, + CFG = 1U << 3U, + BlockLayout = 1U << 4U, + Frame = 1U << 5U, + ConstantPool = 1U << 6U, + JumpTable = 1U << 7U, + TargetState = 1U << 8U, +}; + +class MachinePassChanges final { +public: + constexpr MachinePassChanges() noexcept = default; + constexpr MachinePassChanges(std::initializer_list<MachinePassChange> Changes) noexcept { + for (const MachinePassChange Change : Changes) + add(Change); + } + + [[nodiscard]] static constexpr MachinePassChanges all() noexcept { + return fromRaw((1U << 9U) - 1U); + } + + [[nodiscard]] static constexpr MachinePassChanges fromRaw(std::uint32_t Bits) noexcept { + MachinePassChanges Result; + Result.Bits = Bits & rawMask(); + return Result; + } + + constexpr void add(MachinePassChange Change) noexcept { + Bits |= static_cast<std::uint32_t>(Change); + } + + [[nodiscard]] constexpr bool has(MachinePassChange Change) const noexcept { + return (Bits & static_cast<std::uint32_t>(Change)) != 0; + } + + [[nodiscard]] constexpr bool contains(MachinePassChanges Other) const noexcept { + return (Bits & Other.Bits) == Other.Bits; + } + + [[nodiscard]] constexpr bool intersects(MachinePassChanges Other) const noexcept { + return (Bits & Other.Bits) != 0; + } + + [[nodiscard]] constexpr bool empty() const noexcept { + return Bits == 0; + } + + [[nodiscard]] constexpr std::uint32_t rawValue() const noexcept { + return Bits; + } + + friend constexpr bool operator==(MachinePassChanges Left, + MachinePassChanges Right) noexcept = default; + +private: + [[nodiscard]] static constexpr std::uint32_t rawMask() noexcept { + return (1U << 9U) - 1U; + } + + std::uint32_t Bits = 0; +}; + +class PreservedAnalyses final { +public: + [[nodiscard]] static PreservedAnalyses all() noexcept { + PreservedAnalyses Result; + Result.PreserveAll = true; + return Result; + } + + [[nodiscard]] static PreservedAnalyses none() noexcept { + return {}; + } + + void preserve(AnalysisID ID) { + if (ID != nullptr) + Preserved.insert(ID); + } + + template <typename AnalysisT> void preserve() { + preserve(analysisID<AnalysisT>()); + } + + [[nodiscard]] bool preserves(AnalysisID ID) const noexcept { + return PreserveAll || (ID != nullptr && Preserved.contains(ID)); + } + + [[nodiscard]] bool preservesAll() const noexcept { + return PreserveAll; + } + + template <typename AnalysisT> [[nodiscard]] static AnalysisID analysisID() noexcept { + static const std::uint8_t Token = 0; + return &Token; + } + +private: + bool PreserveAll = false; + std::unordered_set<AnalysisID> Preserved; +}; + +enum class PassThreadSafety : std::uint8_t { + NotThreadSafe, + ThreadSafe, +}; + +struct PassParameter final { + std::string Name; + std::string Description; + std::optional<std::string> DefaultValue; + bool Required = false; +}; + +struct MachinePassRegistrationMetadata { + std::vector<PassParameter> Parameters; + PassThreadSafety ThreadSafety = PassThreadSafety::NotThreadSafe; + MachinePassChanges DeclaredChanges = MachinePassChanges::all(); +}; + +struct MachinePassContract final : MachinePassRegistrationMetadata { + std::string Name; + MachineFunctionProperties Requires; + MachineFunctionProperties Sets; + MachineFunctionProperties Clears; + std::vector<AnalysisID> RequiredAnalyses; + std::optional<PipelineStage> VerificationStage; +}; + +struct MachinePassResult final { + bool Changed = false; + MachinePassChanges Changes; + PreservedAnalyses Preserved = PreservedAnalyses::none(); +}; + +struct CompilationUnitPassContract final { + std::string Name; + std::vector<AnalysisID> RequiredAnalyses; + std::vector<PassParameter> Parameters; + MachinePassChanges DeclaredChanges = MachinePassChanges::all(); +}; + +struct CompilationUnitPassResult final { + bool Changed = false; + MachinePassChanges Changes; + PreservedAnalyses PreservedUnitAnalyses = PreservedAnalyses::none(); + PreservedAnalyses PreservedFunctionAnalyses = PreservedAnalyses::none(); +}; + +struct MachineAnalysisRegistration final { + AnalysisID ID = nullptr; + std::string Name; + std::vector<AnalysisID> Dependencies; + MachinePassChanges InvalidatedBy = MachinePassChanges::all(); + PassThreadSafety ThreadSafety = PassThreadSafety::NotThreadSafe; +}; + +struct CompilationUnitAnalysisRegistration final { + AnalysisID ID = nullptr; + std::string Name; + std::vector<AnalysisID> Dependencies; + MachinePassChanges InvalidatedBy = MachinePassChanges::all(); +}; + +class MachinePassInstrumentation; + +class MachineAnalysisManager final { +public: + MachineAnalysisManager() = default; + MachineAnalysisManager(const MachineAnalysisManager &) = delete; + MachineAnalysisManager &operator=(const MachineAnalysisManager &) = delete; + MachineAnalysisManager(MachineAnalysisManager &&) = delete; + MachineAnalysisManager &operator=(MachineAnalysisManager &&) = delete; + ~MachineAnalysisManager() = default; + + template <typename AnalysisT> [[nodiscard]] static AnalysisID id() noexcept { + return PreservedAnalyses::analysisID<AnalysisT>(); + } + + template <typename AnalysisT> + [[nodiscard]] Expected<void> registerAnalysis(MachineAnalysisRegistration Registration = {}) { + using ResultT = typename AnalysisT::Result; + if (Registration.ID == nullptr) + Registration.ID = id<AnalysisT>(); + if (Registration.Name.empty()) { + if constexpr (requires { + { AnalysisT::name() } -> std::convertible_to<std::string_view>; + }) { + Registration.Name = std::string(AnalysisT::name()); + } else { + Registration.Name = "unnamed-machine-analysis"; + } + } + + ErasedRunner Runner = [](MachineFunction &Function, const TargetDescription &Target, + MachineAnalysisManager &Manager) -> Expected<std::shared_ptr<void>> { + auto Computed = AnalysisT::run(Function, Target, Manager); + if (!Computed) + return std::unexpected(Computed.error()); + return std::shared_ptr<void>(new ResultT(std::move(*Computed)), + [](void *Value) { delete static_cast<ResultT *>(Value); }); + }; + ErasedInvalidator Invalidator = [](void *Value, const MachineFunction &Function, + const PreservedAnalyses &Preserved) -> bool { + if constexpr (requires(ResultT &Result, const MachineFunction &InputFunction, + const PreservedAnalyses &Analyses) { + { Result.invalidate(InputFunction, Analyses) } -> std::convertible_to<bool>; + }) { + return static_cast<ResultT *>(Value)->invalidate(Function, Preserved); + } + return true; + }; + return registerAnalysisImpl(std::move(Registration), std::move(Runner), std::move(Invalidator)); + } + + template <typename AnalysisT> + [[nodiscard]] Expected<typename AnalysisT::Result *> getResult(MachineFunction &Function, + const TargetDescription &Target) { + const AnalysisID Key = id<AnalysisT>(); + if (!isRegistered(Key)) { + auto Registered = registerAnalysis<AnalysisT>(); + if (!Registered) + return std::unexpected(Registered.error()); + } + auto Result = getResultImpl(Key, Function, Target); + if (!Result) + return std::unexpected(Result.error()); + return static_cast<typename AnalysisT::Result *>(*Result); + } + + void invalidate(MachineFunction &Function, const PreservedAnalyses &Preserved, + MachinePassChanges Changes) noexcept; + void invalidate(MachineFunction &Function, const PreservedAnalyses &Preserved) noexcept { + invalidate(Function, Preserved, MachinePassChanges::all()); + } + [[nodiscard]] bool hasCached(const MachineFunction &Function, AnalysisID ID) const noexcept; + [[nodiscard]] bool isRegistered(AnalysisID ID) const noexcept; + [[nodiscard]] std::size_t cachedResultCount(const MachineFunction &Function) const noexcept; + void clear(MachineFunction &Function) noexcept; + void clearAll() noexcept; + + [[nodiscard]] Expected<std::unique_ptr<MachineAnalysisManager>> forkEmpty() const; + [[nodiscard]] Expected<bool> + requestAction(std::string_view Action, const MachineFunction &Function, std::uint64_t Cost = 1); + +private: + using ErasedRunner = std::function<Expected<std::shared_ptr<void>>( + MachineFunction &, const TargetDescription &, MachineAnalysisManager &)>; + using ErasedInvalidator = + std::function<bool(void *, const MachineFunction &, const PreservedAnalyses &)>; + + struct RegisteredAnalysis final { + MachineAnalysisRegistration Info; + ErasedRunner Runner; + ErasedInvalidator Invalidator; + }; + + struct CacheEntry final { + std::shared_ptr<void> Value; + AnalysisID ID = nullptr; + }; + + [[nodiscard]] Expected<void> registerAnalysisImpl(MachineAnalysisRegistration Registration, + ErasedRunner Runner, + ErasedInvalidator Invalidator); + [[nodiscard]] Expected<void *> getResultImpl(AnalysisID ID, MachineFunction &Function, + const TargetDescription &Target); + [[nodiscard]] Expected<void> materializeDependencies(const RegisteredAnalysis &Registration, + MachineFunction &Function, + const TargetDescription &Target); + [[nodiscard]] Expected<void> + validateParallelRequirements(std::span<const AnalysisID> RequiredAnalyses) const; + void setInstrumentation(MachinePassInstrumentation *NewInstrumentation) noexcept { + Instrumentation = NewInstrumentation; + } + + std::unordered_map<AnalysisID, RegisteredAnalysis> Registry; + std::unordered_map<MachineFunction *, std::unordered_map<AnalysisID, CacheEntry>> Cache; + std::unordered_map<MachineFunction *, std::vector<AnalysisID>> ActiveComputations; + MachinePassInstrumentation *Instrumentation = nullptr; + + friend class MachinePassManager; + friend class CompilationUnitPassManager; + friend Expected<void> registerStage8MachineAnalyses(MachineAnalysisManager &Analyses); +}; + +class CompilationUnitAnalysisManager final { +public: + CompilationUnitAnalysisManager() = default; + CompilationUnitAnalysisManager(const CompilationUnitAnalysisManager &) = delete; + CompilationUnitAnalysisManager &operator=(const CompilationUnitAnalysisManager &) = delete; + CompilationUnitAnalysisManager(CompilationUnitAnalysisManager &&) = delete; + CompilationUnitAnalysisManager &operator=(CompilationUnitAnalysisManager &&) = delete; + ~CompilationUnitAnalysisManager() = default; + + template <typename AnalysisT> [[nodiscard]] static AnalysisID id() noexcept { + return PreservedAnalyses::analysisID<AnalysisT>(); + } + + template <typename AnalysisT> + [[nodiscard]] Expected<void> + registerAnalysis(CompilationUnitAnalysisRegistration Registration = {}) { + using ResultT = typename AnalysisT::Result; + if (Registration.ID == nullptr) + Registration.ID = id<AnalysisT>(); + if (Registration.Name.empty()) { + if constexpr (requires { + { AnalysisT::name() } -> std::convertible_to<std::string_view>; + }) { + Registration.Name = std::string(AnalysisT::name()); + } else { + Registration.Name = "unnamed-compilation-unit-analysis"; + } + } + + ErasedRunner Runner = + [](CompilationUnit &Unit, const TargetDescription &Target, + CompilationUnitAnalysisManager &Manager) -> Expected<std::shared_ptr<void>> { + auto Computed = AnalysisT::run(Unit, Target, Manager); + if (!Computed) + return std::unexpected(Computed.error()); + return std::shared_ptr<void>(new ResultT(std::move(*Computed)), + [](void *Value) { delete static_cast<ResultT *>(Value); }); + }; + ErasedInvalidator Invalidator = [](void *Value, const CompilationUnit &Unit, + const PreservedAnalyses &Preserved) -> bool { + if constexpr (requires(ResultT &Result, const CompilationUnit &InputUnit, + const PreservedAnalyses &Analyses) { + { Result.invalidate(InputUnit, Analyses) } -> std::convertible_to<bool>; + }) { + return static_cast<ResultT *>(Value)->invalidate(Unit, Preserved); + } + return true; + }; + return registerAnalysisImpl(std::move(Registration), std::move(Runner), std::move(Invalidator)); + } + + template <typename AnalysisT> + [[nodiscard]] Expected<typename AnalysisT::Result *> getResult(CompilationUnit &Unit, + const TargetDescription &Target) { + const AnalysisID Key = id<AnalysisT>(); + if (!isRegistered(Key)) { + auto Registered = registerAnalysis<AnalysisT>(); + if (!Registered) + return std::unexpected(Registered.error()); + } + auto Result = getResultImpl(Key, Unit, Target); + if (!Result) + return std::unexpected(Result.error()); + return static_cast<typename AnalysisT::Result *>(*Result); + } + + void invalidate(CompilationUnit &Unit, const PreservedAnalyses &Preserved, + MachinePassChanges Changes) noexcept; + [[nodiscard]] bool hasCached(const CompilationUnit &Unit, AnalysisID ID) const noexcept; + [[nodiscard]] bool isRegistered(AnalysisID ID) const noexcept; + void clear(CompilationUnit &Unit) noexcept; + void clearAll() noexcept; + +private: + using ErasedRunner = std::function<Expected<std::shared_ptr<void>>( + CompilationUnit &, const TargetDescription &, CompilationUnitAnalysisManager &)>; + using ErasedInvalidator = + std::function<bool(void *, const CompilationUnit &, const PreservedAnalyses &)>; + + struct RegisteredAnalysis final { + CompilationUnitAnalysisRegistration Info; + ErasedRunner Runner; + ErasedInvalidator Invalidator; + }; + + struct CacheEntry final { + std::shared_ptr<void> Value; + AnalysisID ID = nullptr; + }; + + [[nodiscard]] Expected<void> + registerAnalysisImpl(CompilationUnitAnalysisRegistration Registration, ErasedRunner Runner, + ErasedInvalidator Invalidator); + [[nodiscard]] Expected<void *> getResultImpl(AnalysisID ID, CompilationUnit &Unit, + const TargetDescription &Target); + [[nodiscard]] Expected<void> materializeDependencies(const RegisteredAnalysis &Registration, + CompilationUnit &Unit, + const TargetDescription &Target); + void setInstrumentation(MachinePassInstrumentation *NewInstrumentation) noexcept { + Instrumentation = NewInstrumentation; + } + + std::unordered_map<AnalysisID, RegisteredAnalysis> Registry; + std::unordered_map<CompilationUnit *, std::unordered_map<AnalysisID, CacheEntry>> Cache; + std::unordered_map<CompilationUnit *, std::vector<AnalysisID>> ActiveComputations; + MachinePassInstrumentation *Instrumentation = nullptr; + + friend class CompilationUnitPassManager; +}; + +class MachineFunctionPass { +public: + MachineFunctionPass() = default; + MachineFunctionPass(const MachineFunctionPass &) = delete; + MachineFunctionPass &operator=(const MachineFunctionPass &) = delete; + virtual ~MachineFunctionPass() = default; + + [[nodiscard]] virtual const MachinePassContract &contract() const noexcept = 0; + [[nodiscard]] virtual Expected<MachinePassResult> run(MachineFunction &Function, + const TargetDescription &Target, + MachineAnalysisManager &Analyses) = 0; +}; + +class CompilationUnitPass { +public: + CompilationUnitPass() = default; + CompilationUnitPass(const CompilationUnitPass &) = delete; + CompilationUnitPass &operator=(const CompilationUnitPass &) = delete; + virtual ~CompilationUnitPass() = default; + + [[nodiscard]] virtual const CompilationUnitPassContract &contract() const noexcept = 0; + [[nodiscard]] virtual Expected<CompilationUnitPassResult> + run(CompilationUnit &Unit, const TargetDescription &Target, + CompilationUnitAnalysisManager &UnitAnalyses, MachineAnalysisManager &FunctionAnalyses) = 0; +}; + +enum class InstrumentationPhase : std::uint8_t { + Before, + After, +}; + +struct InstrumentationStatistic final { + std::string Name; + bool IsAnalysis = false; + std::uint64_t Invocations = 0; + std::uint64_t CacheHits = 0; + std::uint64_t Changes = 0; + std::uint64_t Failures = 0; + std::uint64_t TotalNanoseconds = 0; +}; + +class MachinePassInstrumentation final { +public: + using BeforeCallback = std::function<void(std::string_view, const MachineFunction &)>; + using AfterCallback = + std::function<void(std::string_view, const MachineFunction &, const MachinePassResult &)>; + using FailureCallback = + std::function<void(std::string_view, const MachineFunction &, const Error &)>; + using BeforeAnalysisCallback = std::function<void(std::string_view, const MachineFunction &)>; + using AfterAnalysisCallback = + std::function<void(std::string_view, const MachineFunction &, bool, std::uint64_t)>; + using AnalysisFailureCallback = + std::function<void(std::string_view, const MachineFunction &, const Error &)>; + using IRPrintCallback = + std::function<void(InstrumentationPhase, std::string_view, const MachineFunction &)>; + using ChangeCallback = + std::function<void(std::string_view, const MachineFunction &, MachinePassChanges, bool)>; + using ActionFilter = + std::function<bool(std::string_view, const MachineFunction &, std::uint64_t)>; + + using BeforeUnitCallback = std::function<void(std::string_view, const CompilationUnit &)>; + using AfterUnitCallback = std::function<void(std::string_view, const CompilationUnit &, + const CompilationUnitPassResult &)>; + using UnitFailureCallback = + std::function<void(std::string_view, const CompilationUnit &, const Error &)>; + using BeforeUnitAnalysisCallback = std::function<void(std::string_view, const CompilationUnit &)>; + using AfterUnitAnalysisCallback = + std::function<void(std::string_view, const CompilationUnit &, bool, std::uint64_t)>; + using UnitAnalysisFailureCallback = + std::function<void(std::string_view, const CompilationUnit &, const Error &)>; + + void addBeforeCallback(BeforeCallback Callback); + void addAfterCallback(AfterCallback Callback); + void addFailureCallback(FailureCallback Callback); + void addBeforeAnalysisCallback(BeforeAnalysisCallback Callback); + void addAfterAnalysisCallback(AfterAnalysisCallback Callback); + void addAnalysisFailureCallback(AnalysisFailureCallback Callback); + void addIRPrintCallback(IRPrintCallback Callback); + void addChangeCallback(ChangeCallback Callback); + void setActionFilter(ActionFilter Filter); + void setPerFunctionFuel(std::optional<std::uint64_t> Fuel); + + void addBeforeUnitCallback(BeforeUnitCallback Callback); + void addAfterUnitCallback(AfterUnitCallback Callback); + void addUnitFailureCallback(UnitFailureCallback Callback); + void addBeforeUnitAnalysisCallback(BeforeUnitAnalysisCallback Callback); + void addAfterUnitAnalysisCallback(AfterUnitAnalysisCallback Callback); + void addUnitAnalysisFailureCallback(UnitAnalysisFailureCallback Callback); + + [[nodiscard]] std::vector<InstrumentationStatistic> statistics() const; + void clearStatistics(); + +private: + struct BufferedEvents final { + const TargetDescription *Target = nullptr; + std::vector<std::function<void()>> Events; + }; + + [[nodiscard]] bool bufferFunctionEvent(const MachineFunction &Function, + std::function<void(const MachineFunction &)> Replay) const; + void beginBuffering(BufferedEvents &Buffer, const TargetDescription &Target) const noexcept; + void endBuffering() const noexcept; + void replayBufferedEvents(BufferedEvents &Buffer) const; + + void before(std::string_view Name, const MachineFunction &Function) const; + void after(std::string_view Name, const MachineFunction &Function, + const MachinePassResult &Result, std::uint64_t Nanoseconds) const; + void failure(std::string_view Name, const MachineFunction &Function, const Error &ErrorValue, + std::uint64_t Nanoseconds = 0) const; + void beforeAnalysis(std::string_view Name, const MachineFunction &Function) const; + void afterAnalysis(std::string_view Name, const MachineFunction &Function, bool CacheHit, + std::uint64_t Nanoseconds) const; + void analysisFailure(std::string_view Name, const MachineFunction &Function, + const Error &ErrorValue, std::uint64_t Nanoseconds) const; + void change(std::string_view Name, const MachineFunction &Function, MachinePassChanges Changes, + bool FingerprintChanged) const; + [[nodiscard]] Expected<bool> requestAction(std::string_view Action, + const MachineFunction &Function, std::uint64_t Cost); + + void beforeUnit(std::string_view Name, const CompilationUnit &Unit) const; + void afterUnit(std::string_view Name, const CompilationUnit &Unit, + const CompilationUnitPassResult &Result, std::uint64_t Nanoseconds) const; + void unitFailure(std::string_view Name, const CompilationUnit &Unit, const Error &ErrorValue, + std::uint64_t Nanoseconds = 0) const; + void beforeUnitAnalysis(std::string_view Name, const CompilationUnit &Unit) const; + void afterUnitAnalysis(std::string_view Name, const CompilationUnit &Unit, bool CacheHit, + std::uint64_t Nanoseconds) const; + void unitAnalysisFailure(std::string_view Name, const CompilationUnit &Unit, + const Error &ErrorValue, std::uint64_t Nanoseconds) const; + + [[nodiscard]] InstrumentationStatistic &statistic(std::string_view Name, bool IsAnalysis) const; + + mutable std::mutex Mutex; + mutable std::mutex ActionMutex; + std::vector<BeforeCallback> Before; + std::vector<AfterCallback> After; + std::vector<FailureCallback> Failure; + std::vector<BeforeAnalysisCallback> BeforeAnalysis; + std::vector<AfterAnalysisCallback> AfterAnalysis; + std::vector<AnalysisFailureCallback> AnalysisFailure; + std::vector<IRPrintCallback> IRPrint; + std::vector<ChangeCallback> Change; + ActionFilter Filter; + std::optional<std::uint64_t> PerFunctionFuel; + std::unordered_map<std::uint64_t, std::uint64_t> ConsumedFuel; + + std::vector<BeforeUnitCallback> BeforeUnit; + std::vector<AfterUnitCallback> AfterUnit; + std::vector<UnitFailureCallback> UnitFailure; + std::vector<BeforeUnitAnalysisCallback> BeforeUnitAnalysis; + std::vector<AfterUnitAnalysisCallback> AfterUnitAnalysis; + std::vector<UnitAnalysisFailureCallback> UnitAnalysisFailure; + mutable std::unordered_map<std::string, InstrumentationStatistic> Statistics; + + static thread_local BufferedEvents *ActiveBuffer; + + friend class CompilationUnitAnalysisManager; + friend class CompilationUnitPassManager; + friend class MachineAnalysisManager; + friend class MachinePassManager; +}; + +struct MachinePassManagerOptions final { + bool VerifyBefore = true; + bool VerifyEach = true; + bool DetectUnreportedChanges = false; +}; + +class MachinePassManager final { +public: + explicit MachinePassManager(MachinePassManagerOptions Options = {}) : Options(Options) {} + + MachinePassManager(const MachinePassManager &) = delete; + MachinePassManager &operator=(const MachinePassManager &) = delete; + + [[nodiscard]] Expected<void> addPass(std::unique_ptr<MachineFunctionPass> Pass); + [[nodiscard]] Expected<void> run(MachineFunction &Function, const TargetDescription &Target, + MachineAnalysisManager &Analyses, + MachinePassInstrumentation *Instrumentation = nullptr) const; + [[nodiscard]] Expected<void> + runFunctions(CompilationUnit &Unit, const TargetDescription &Target, + const MachineAnalysisManager &AnalysisPrototype, std::size_t ThreadCount, + MachinePassInstrumentation *Instrumentation = nullptr) const; + + [[nodiscard]] std::size_t size() const noexcept { + return Passes.size(); + } + +private: + [[nodiscard]] Expected<void> validateContract(const MachinePassContract &Contract) const; + + MachinePassManagerOptions Options; + std::vector<std::unique_ptr<MachineFunctionPass>> Passes; +}; + +struct CompilationUnitPassManagerOptions final { + bool VerifyBefore = true; + bool VerifyEach = true; +}; + +class CompilationUnitPassManager final { +public: + explicit CompilationUnitPassManager(CompilationUnitPassManagerOptions Options = {}) + : Options(Options) {} + + CompilationUnitPassManager(const CompilationUnitPassManager &) = delete; + CompilationUnitPassManager &operator=(const CompilationUnitPassManager &) = delete; + + [[nodiscard]] Expected<void> addPass(std::unique_ptr<CompilationUnitPass> Pass); + [[nodiscard]] Expected<void> run(CompilationUnit &Unit, const TargetDescription &Target, + CompilationUnitAnalysisManager &UnitAnalyses, + MachineAnalysisManager &FunctionAnalyses, + MachinePassInstrumentation *Instrumentation = nullptr) const; + +private: + CompilationUnitPassManagerOptions Options; + std::vector<std::unique_ptr<CompilationUnitPass>> Passes; +}; + +} // namespace rcc + +#endif // RCC_CODEGEN_MACHINEPASS_H diff --git a/backend/include/rcc/CodeGen/TargetCallLowering.h b/backend/include/rcc/CodeGen/TargetCallLowering.h new file mode 100644 index 0000000..a6b3535 --- /dev/null +++ b/backend/include/rcc/CodeGen/TargetCallLowering.h @@ -0,0 +1,404 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef RCC_CODEGEN_TARGETCALLLOWERING_H +#define RCC_CODEGEN_TARGETCALLLOWERING_H + +#include "rcc/CodeGen/LowLevelType.h" +#include "rcc/CodeGen/MachineIRTypes.h" +#include "rcc/CodeGen/Register.h" +#include "rcc/CodeGen/RegisterMask.h" +#include "rcc/Support/Error.h" + +#include <cstddef> +#include <cstdint> +#include <initializer_list> +#include <memory> +#include <optional> +#include <span> +#include <string> +#include <string_view> +#include <utility> +#include <variant> +#include <vector> + +namespace rcc { + +class MachineIRBuilder; + +enum class ABIExtensionKind : std::uint8_t { + None, + AnyExtend, + SignExtend, + ZeroExtend, + Count, +}; + +enum class ABIValueFlag : std::uint8_t { + ByVal, + StructReturn, + Indirect, + InRegister, + Count, +}; + +class ABIValueFlags final { +public: + constexpr ABIValueFlags() noexcept = default; + + ABIValueFlags(std::initializer_list<ABIValueFlag> Flags) noexcept; + + [[nodiscard]] constexpr bool has(ABIValueFlag Flag) const noexcept { + const auto Index = static_cast<std::uint32_t>(Flag); + return Index < static_cast<std::uint32_t>(ABIValueFlag::Count) && + (Bits & (std::uint8_t{1} << Index)) != 0; + } + + constexpr void set(ABIValueFlag Flag) noexcept { + const auto Index = static_cast<std::uint32_t>(Flag); + if (Index < static_cast<std::uint32_t>(ABIValueFlag::Count)) + Bits |= std::uint8_t{1} << Index; + } + + [[nodiscard]] constexpr std::uint8_t rawValue() const noexcept { + return Bits; + } + + friend constexpr bool operator==(ABIValueFlags Left, ABIValueFlags Right) noexcept = default; + +private: + std::uint8_t Bits = 0; +}; + +struct ABIValue final { + Register Value; + LLT Type; + std::uint32_t OriginalValue = 0; + std::uint16_t FragmentIndex = 0; + std::uint16_t FragmentCount = 1; + std::uint32_t FragmentOffsetBytes = 0; + Alignment OriginalAlignment; + ABIExtensionKind Extension = ABIExtensionKind::None; + ABIValueFlags Flags; + std::uint64_t ByValSizeBytes = 0; + Alignment ByValAlignment; + + friend bool operator==(const ABIValue &Left, const ABIValue &Right) = default; +}; + +enum class MachineCallTargetKind : std::uint8_t { + Invalid, + GlobalSymbol, + ExternalSymbol, + IndirectRegister, +}; + +class MachineCallTarget final { +public: + constexpr MachineCallTarget() noexcept = default; + + [[nodiscard]] static Expected<MachineCallTarget> globalSymbol(std::string Name, + std::uint32_t TargetFlags = 0); + [[nodiscard]] static Expected<MachineCallTarget> externalSymbol(std::string Name, + std::uint32_t TargetFlags = 0); + [[nodiscard]] static Expected<MachineCallTarget> indirect(Register Callee, + std::uint32_t TargetFlags = 0); + + [[nodiscard]] MachineCallTargetKind kind() const noexcept { + return Kind; + } + + [[nodiscard]] std::string_view symbolName() const noexcept; + [[nodiscard]] Register indirectRegister() const noexcept; + [[nodiscard]] std::uint32_t targetFlags() const noexcept { + return TargetFlags; + } + + [[nodiscard]] bool isValid() const noexcept { + return Kind != MachineCallTargetKind::Invalid; + } + + friend bool operator==(const MachineCallTarget &Left, const MachineCallTarget &Right) = default; + +private: + using Storage = std::variant<std::monostate, std::string, Register>; + + MachineCallTarget(MachineCallTargetKind Kind, Storage Value, std::uint32_t TargetFlags) noexcept + : Kind(Kind), Value(std::move(Value)), TargetFlags(TargetFlags) {} + + MachineCallTargetKind Kind = MachineCallTargetKind::Invalid; + Storage Value; + std::uint32_t TargetFlags = 0; +}; + +enum class TailCallKind : std::uint8_t { + NotTail, + Tail, + MustTail, +}; + +struct TailCallContext final { + CallingConventionID CallerConvention; + std::vector<ABIValue> CallerReturns; + std::uint64_t ReusableIncomingArgumentBytes = 0; + std::size_t CallerFixedArgumentCount = 0; + bool CallerIsVariadic = false; + bool CallerHasDynamicStackAllocation = false; + bool CallerUsesStructReturn = false; +}; + +struct FormalArgumentRequest final { + CallingConventionID Convention; + std::vector<ABIValue> Arguments; + std::size_t FixedArgumentCount = 0; + bool IsVariadic = false; +}; + +struct CallLoweringRequest final { + CallingConventionID Convention; + MachineCallTarget Callee; + std::vector<ABIValue> Arguments; + std::vector<ABIValue> Results; + std::size_t FixedArgumentCount = 0; + std::uint64_t CallSiteID = 0; + bool IsVariadic = false; + TailCallKind TailKind = TailCallKind::NotTail; + std::optional<TailCallContext> TailContext; +}; + +struct ReturnLoweringRequest final { + CallingConventionID Convention; + std::vector<ABIValue> Values; + bool FunctionIsVariadic = false; +}; + +enum class CCLocationKind : std::uint8_t { + Register, + Stack, + Indirect, + Custom, +}; + +enum class CCAssignmentFlag : std::uint8_t { + Variadic, + ByVal, + StructReturn, + Indirect, + InRegister, + Bitcast, + Count, +}; + +class CCAssignmentFlags final { +public: + constexpr CCAssignmentFlags() noexcept = default; + + CCAssignmentFlags(std::initializer_list<CCAssignmentFlag> Flags) noexcept; + + [[nodiscard]] constexpr bool has(CCAssignmentFlag Flag) const noexcept { + const auto Index = static_cast<std::uint32_t>(Flag); + return Index < static_cast<std::uint32_t>(CCAssignmentFlag::Count) && + (Bits & (std::uint8_t{1} << Index)) != 0; + } + + constexpr void set(CCAssignmentFlag Flag) noexcept { + const auto Index = static_cast<std::uint32_t>(Flag); + if (Index < static_cast<std::uint32_t>(CCAssignmentFlag::Count)) + Bits |= std::uint8_t{1} << Index; + } + + [[nodiscard]] constexpr std::uint8_t rawValue() const noexcept { + return Bits; + } + + friend constexpr bool operator==(CCAssignmentFlags Left, + CCAssignmentFlags Right) noexcept = default; + +private: + std::uint8_t Bits = 0; +}; + +struct CCAssignment final { + std::size_t ValueIndex = 0; + Register OriginalValue; + std::uint32_t OriginalValueIndex = 0; + std::uint16_t FragmentIndex = 0; + std::uint16_t FragmentCount = 1; + LLT ValueType; + LLT LocationType; + CCLocationKind LocationKind = CCLocationKind::Register; + std::optional<PhysicalRegister> LocationRegister; + std::optional<std::uint64_t> StackOffsetBytes; + std::uint64_t LocationSizeBytes = 0; + std::uint64_t StackSlotSizeBytes = 0; + Alignment LocationAlignment; + ABIExtensionKind Extension = ABIExtensionKind::None; + CCAssignmentFlags CustomFlags; + + friend bool operator==(const CCAssignment &Left, const CCAssignment &Right) = default; +}; + +struct StackArgumentArea final { + std::uint64_t SizeBytes = 0; + std::uint64_t ShadowSpaceBytes = 0; + Alignment Align; + + friend bool operator==(StackArgumentArea Left, StackArgumentArea Right) noexcept = default; +}; + +struct CallFrameRequirements final { + std::uint64_t SizeBytes = 0; + Alignment Align; + bool EmitSetup = false; + bool EmitDestroy = false; + bool ReusesIncomingArea = false; + + friend bool operator==(CallFrameRequirements Left, + CallFrameRequirements Right) noexcept = default; +}; + +struct VarArgRegisterSave final { + PhysicalRegister Reg; + std::uint64_t OffsetBytes = 0; + + friend bool operator==(VarArgRegisterSave Left, VarArgRegisterSave Right) noexcept = default; +}; + +struct VarArgLoweringState final { + bool IsVariadic = false; + std::size_t FixedArgumentCount = 0; + std::size_t FirstUnallocatedIntegerRegister = 0; + std::uint64_t OverflowAreaOffsetBytes = 0; + std::int64_t RegisterSaveAreaOffsetBytes = 0; + std::uint64_t RegisterSaveAreaSizeBytes = 0; + std::uint64_t RegisterSavePaddingBytes = 0; + std::vector<VarArgRegisterSave> RegistersToSave; + + friend bool operator==(const VarArgLoweringState &Left, + const VarArgLoweringState &Right) = default; +}; + +struct ByValCopyAssignment final { + std::size_t ArgumentAssignmentIndex = 0; + Register Source; + LLT PointerType; + std::uint64_t StackOffsetBytes = 0; + std::uint64_t SizeBytes = 0; + Alignment Align; + + friend bool operator==(ByValCopyAssignment Left, ByValCopyAssignment Right) noexcept = default; +}; + +enum class CallLoweringPlanKind : std::uint8_t { + FormalArguments, + Call, + Return, +}; + +struct CallLoweringPlanDesc final { + CallLoweringPlanKind Kind = CallLoweringPlanKind::FormalArguments; + std::string Target; + CallingConventionID Convention; + std::vector<CCAssignment> ArgumentAssignments; + std::vector<CCAssignment> ReturnAssignments; + StackArgumentArea StackArguments; + CallFrameRequirements CallFrame; + VarArgLoweringState VarArgs; + std::vector<ByValCopyAssignment> ByValCopies; + std::shared_ptr<const RegisterMask> PreservedMask; + std::optional<MachineCallTarget> Callee; + std::uint64_t CallSiteID = 0; + TailCallKind TailDecision = TailCallKind::NotTail; + std::string TailRejectionReason; +}; + +class CallLoweringPlan final { +public: + [[nodiscard]] static Expected<CallLoweringPlan> create(CallLoweringPlanDesc Description); + + [[nodiscard]] CallLoweringPlanKind kind() const noexcept { + return Description.Kind; + } + + [[nodiscard]] std::string_view target() const noexcept { + return Description.Target; + } + + [[nodiscard]] CallingConventionID convention() const noexcept { + return Description.Convention; + } + + [[nodiscard]] std::span<const CCAssignment> argumentAssignments() const noexcept { + return Description.ArgumentAssignments; + } + + [[nodiscard]] std::span<const CCAssignment> returnAssignments() const noexcept { + return Description.ReturnAssignments; + } + + [[nodiscard]] const StackArgumentArea &stackArguments() const noexcept { + return Description.StackArguments; + } + + [[nodiscard]] const CallFrameRequirements &callFrame() const noexcept { + return Description.CallFrame; + } + + [[nodiscard]] const VarArgLoweringState &varArgs() const noexcept { + return Description.VarArgs; + } + + [[nodiscard]] std::span<const ByValCopyAssignment> byValCopies() const noexcept { + return Description.ByValCopies; + } + + [[nodiscard]] const std::shared_ptr<const RegisterMask> &preservedMask() const noexcept { + return Description.PreservedMask; + } + + [[nodiscard]] const MachineCallTarget *callee() const noexcept { + return Description.Callee ? &*Description.Callee : nullptr; + } + + [[nodiscard]] std::uint64_t callSiteID() const noexcept { + return Description.CallSiteID; + } + + [[nodiscard]] TailCallKind tailDecision() const noexcept { + return Description.TailDecision; + } + + [[nodiscard]] std::string_view tailRejectionReason() const noexcept { + return Description.TailRejectionReason; + } + +private: + explicit CallLoweringPlan(CallLoweringPlanDesc Description) + : Description(std::move(Description)) {} + + CallLoweringPlanDesc Description; +}; + +class TargetCallLowering { +public: + virtual ~TargetCallLowering() = default; + + [[nodiscard]] Expected<void> lowerFormalArguments(MachineIRBuilder &Builder, + const FormalArgumentRequest &Request) const; + [[nodiscard]] Expected<void> lowerCall(MachineIRBuilder &Builder, + const CallLoweringRequest &Request) const; + [[nodiscard]] Expected<void> lowerReturn(MachineIRBuilder &Builder, + const ReturnLoweringRequest &Request) const; + + [[nodiscard]] virtual Expected<CallLoweringPlan> + planFormalArguments(const FormalArgumentRequest &Request) const = 0; + [[nodiscard]] virtual Expected<CallLoweringPlan> + planCall(const CallLoweringRequest &Request) const = 0; + [[nodiscard]] virtual Expected<CallLoweringPlan> + planReturn(const ReturnLoweringRequest &Request) const = 0; + [[nodiscard]] virtual Expected<void> emitPlan(MachineIRBuilder &Builder, + const CallLoweringPlan &Plan) const = 0; +}; + +} // namespace rcc + +#endif // RCC_CODEGEN_TARGETCALLLOWERING_H |
