From f99ef4322a7a2c09380fff61f88ab9440f05a92c Mon Sep 17 00:00:00 2001 From: Richard-Qin-X Date: Fri, 7 Aug 2026 22:06:28 +0800 Subject: [CodeGen] Complete machine pass and ABI lowering infrastructure --- backend/include/rcc/CodeGen/GenericOpcode.def | 336 +++++++++++ backend/include/rcc/CodeGen/GenericOpcodes.h | 68 +++ backend/include/rcc/CodeGen/MachineAnalyses.h | 244 ++++++++ backend/include/rcc/CodeGen/MachineIRBuilder.h | 10 + backend/include/rcc/CodeGen/MachineIRTypes.h | 3 + backend/include/rcc/CodeGen/MachinePass.h | 655 +++++++++++++++++++++ backend/include/rcc/CodeGen/TargetCallLowering.h | 404 +++++++++++++ .../include/rcc/Target/RISCV/RISCVCallLowering.h | 43 ++ 8 files changed, 1763 insertions(+) create mode 100644 backend/include/rcc/CodeGen/GenericOpcode.def create mode 100644 backend/include/rcc/CodeGen/GenericOpcodes.h create mode 100644 backend/include/rcc/CodeGen/MachineAnalyses.h create mode 100644 backend/include/rcc/CodeGen/MachinePass.h create mode 100644 backend/include/rcc/CodeGen/TargetCallLowering.h create mode 100644 backend/include/rcc/Target/RISCV/RISCVCallLowering.h (limited to 'backend/include/rcc') 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 +#include +#include +#include + +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(Generic)); +} + +[[nodiscard]] constexpr bool isGenericOpcode(Opcode Value) noexcept { + return Value.value() >= static_cast(GenericOpcode::G_ASSERT_SEXT) && + Value.value() < static_cast(GenericOpcode::G_GENERIC_END); +} + +[[nodiscard]] constexpr bool isCorePseudoOpcode(Opcode Value) noexcept { + return Value.value() >= static_cast(GenericOpcode::PHI) && + Value.value() < static_cast(GenericOpcode::CORE_PSEUDO_END); +} + +inline constexpr std::size_t CorePseudoOpcodeCount = + static_cast(GenericOpcode::CORE_PSEUDO_END) - + static_cast(GenericOpcode::PHI); + +inline constexpr std::size_t GenericOpcodeCount = + static_cast(GenericOpcode::G_GENERIC_END) - + static_cast(GenericOpcode::G_ASSERT_SEXT); + +[[nodiscard]] std::string_view getGenericOpcodeName(GenericOpcode OpcodeValue) noexcept; + +[[nodiscard]] std::span genericInstructionDescriptors() noexcept; + +[[nodiscard]] std::span genericImmediatePredicates() noexcept; + +[[nodiscard]] Expected +appendGenericInstructionInfo(std::vector &Descriptors, + std::vector &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 +#include +#include +#include +#include +#include +#include + +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 unreachableBlocks() const noexcept { + return UnreachableBlocks; + } + + [[nodiscard]] Expected updateAfterCFGChange(MachineFunction &Function); + + private: + [[nodiscard]] Expected build(MachineFunction &Function); + + std::vector Blocks; + std::unordered_map BlockToIndex; + std::vector> Dominators; + std::vector ImmediateDominators; + std::vector Reachable; + std::vector UnreachableBlocks; + + friend class MachineDominatorTreeAnalysis; + }; + + [[nodiscard]] static constexpr std::string_view name() noexcept { + return "MachineDominatorTree"; + } + + [[nodiscard]] static Expected + run(MachineFunction &Function, const TargetDescription &Target, MachineAnalysisManager &Analyses); +}; + +struct MachineLoop final { + MachineBasicBlock *Header = nullptr; + std::vector Blocks; + std::vector Latches; + std::size_t Parent = static_cast(-1); + std::vector Children; + std::uint32_t Depth = 1; +}; + +struct IrreducibleMachineRegion final { + std::vector Blocks; + std::vector Entries; +}; + +class MachineLoopAnalysis final { +public: + class Result final { + public: + [[nodiscard]] std::span loops() const noexcept { + return Loops; + } + [[nodiscard]] std::span 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 Loops; + std::vector IrreducibleRegions; + std::unordered_map InnermostLoop; + std::unordered_set IrreducibleBlocks; + + friend class MachineLoopAnalysis; + }; + + [[nodiscard]] static constexpr std::string_view name() noexcept { + return "MachineLoopInfo"; + } + + [[nodiscard]] static Expected + 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 + successors(const MachineBasicBlock &Block) const noexcept; + + private: + std::unordered_map> Probabilities; + + friend class MachineBranchProbabilityAnalysis; + }; + + [[nodiscard]] static constexpr std::string_view name() noexcept { + return "MachineBranchProbability"; + } + + [[nodiscard]] static Expected + 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 Frequencies; + + friend class MachineBlockFrequencyAnalysis; + }; + + [[nodiscard]] static constexpr std::string_view name() noexcept { + return "MachineBlockFrequency"; + } + + [[nodiscard]] static Expected + 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 + 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 Instructions; +}; + +class MachineMemoryDependenceAnalysis final { +public: + class Result final { + public: + [[nodiscard]] std::span regions() const noexcept { + return Regions; + } + [[nodiscard]] const MachineMemoryDependenceRegion * + regionFor(const MachineBasicBlock &Block) const noexcept; + [[nodiscard]] std::span + dependencies(const MachineBasicBlock &Block) const noexcept; + [[nodiscard]] std::span + dependencies(const MachineInstr &Instruction) const noexcept; + [[nodiscard]] std::span allDependencies() const noexcept { + return Dependencies; + } + + private: + struct Range final { + std::size_t Begin = 0; + std::size_t Size = 0; + }; + + std::vector Dependencies; + std::vector Regions; + std::unordered_map BlockToRegion; + std::unordered_map BlockRanges; + std::unordered_map DestinationRanges; + + friend class MachineMemoryDependenceAnalysis; + }; + + [[nodiscard]] static constexpr std::string_view name() noexcept { + return "MachineMemoryDependence"; + } + + [[nodiscard]] static Expected + run(MachineFunction &Function, const TargetDescription &Target, MachineAnalysisManager &Analyses); +}; + +[[nodiscard]] Expected 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 verifyInsertPoint() const; + [[nodiscard]] Expected setInsertPoint(MachineBasicBlock &Block); [[nodiscard]] Expected setInsertPointBefore(MachineInstr &Instruction); [[nodiscard]] Expected 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; using TargetConstantTypeID = MachineIndex; using TargetFunctionStateTypeID = MachineIndex; using TargetRelocationKindID = MachineIndex; +using CallingConventionID = MachineIndex; 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); static_assert(std::is_trivially_copyable_v); 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 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(Change); + } + + [[nodiscard]] constexpr bool has(MachinePassChange Change) const noexcept { + return (Bits & static_cast(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 void preserve() { + preserve(analysisID()); + } + + [[nodiscard]] bool preserves(AnalysisID ID) const noexcept { + return PreserveAll || (ID != nullptr && Preserved.contains(ID)); + } + + [[nodiscard]] bool preservesAll() const noexcept { + return PreserveAll; + } + + template [[nodiscard]] static AnalysisID analysisID() noexcept { + static const std::uint8_t Token = 0; + return &Token; + } + +private: + bool PreserveAll = false; + std::unordered_set Preserved; +}; + +enum class PassThreadSafety : std::uint8_t { + NotThreadSafe, + ThreadSafe, +}; + +struct PassParameter final { + std::string Name; + std::string Description; + std::optional DefaultValue; + bool Required = false; +}; + +struct MachinePassRegistrationMetadata { + std::vector Parameters; + PassThreadSafety ThreadSafety = PassThreadSafety::NotThreadSafe; + MachinePassChanges DeclaredChanges = MachinePassChanges::all(); +}; + +struct MachinePassContract final : MachinePassRegistrationMetadata { + std::string Name; + MachineFunctionProperties Requires; + MachineFunctionProperties Sets; + MachineFunctionProperties Clears; + std::vector RequiredAnalyses; + std::optional VerificationStage; +}; + +struct MachinePassResult final { + bool Changed = false; + MachinePassChanges Changes; + PreservedAnalyses Preserved = PreservedAnalyses::none(); +}; + +struct CompilationUnitPassContract final { + std::string Name; + std::vector RequiredAnalyses; + std::vector 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 Dependencies; + MachinePassChanges InvalidatedBy = MachinePassChanges::all(); + PassThreadSafety ThreadSafety = PassThreadSafety::NotThreadSafe; +}; + +struct CompilationUnitAnalysisRegistration final { + AnalysisID ID = nullptr; + std::string Name; + std::vector 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 [[nodiscard]] static AnalysisID id() noexcept { + return PreservedAnalyses::analysisID(); + } + + template + [[nodiscard]] Expected registerAnalysis(MachineAnalysisRegistration Registration = {}) { + using ResultT = typename AnalysisT::Result; + if (Registration.ID == nullptr) + Registration.ID = id(); + if (Registration.Name.empty()) { + if constexpr (requires { + { AnalysisT::name() } -> std::convertible_to; + }) { + Registration.Name = std::string(AnalysisT::name()); + } else { + Registration.Name = "unnamed-machine-analysis"; + } + } + + ErasedRunner Runner = [](MachineFunction &Function, const TargetDescription &Target, + MachineAnalysisManager &Manager) -> Expected> { + auto Computed = AnalysisT::run(Function, Target, Manager); + if (!Computed) + return std::unexpected(Computed.error()); + return std::shared_ptr(new ResultT(std::move(*Computed)), + [](void *Value) { delete static_cast(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; + }) { + return static_cast(Value)->invalidate(Function, Preserved); + } + return true; + }; + return registerAnalysisImpl(std::move(Registration), std::move(Runner), std::move(Invalidator)); + } + + template + [[nodiscard]] Expected getResult(MachineFunction &Function, + const TargetDescription &Target) { + const AnalysisID Key = id(); + if (!isRegistered(Key)) { + auto Registered = registerAnalysis(); + if (!Registered) + return std::unexpected(Registered.error()); + } + auto Result = getResultImpl(Key, Function, Target); + if (!Result) + return std::unexpected(Result.error()); + return static_cast(*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> forkEmpty() const; + [[nodiscard]] Expected + requestAction(std::string_view Action, const MachineFunction &Function, std::uint64_t Cost = 1); + +private: + using ErasedRunner = std::function>( + MachineFunction &, const TargetDescription &, MachineAnalysisManager &)>; + using ErasedInvalidator = + std::function; + + struct RegisteredAnalysis final { + MachineAnalysisRegistration Info; + ErasedRunner Runner; + ErasedInvalidator Invalidator; + }; + + struct CacheEntry final { + std::shared_ptr Value; + AnalysisID ID = nullptr; + }; + + [[nodiscard]] Expected registerAnalysisImpl(MachineAnalysisRegistration Registration, + ErasedRunner Runner, + ErasedInvalidator Invalidator); + [[nodiscard]] Expected getResultImpl(AnalysisID ID, MachineFunction &Function, + const TargetDescription &Target); + [[nodiscard]] Expected materializeDependencies(const RegisteredAnalysis &Registration, + MachineFunction &Function, + const TargetDescription &Target); + [[nodiscard]] Expected + validateParallelRequirements(std::span RequiredAnalyses) const; + void setInstrumentation(MachinePassInstrumentation *NewInstrumentation) noexcept { + Instrumentation = NewInstrumentation; + } + + std::unordered_map Registry; + std::unordered_map> Cache; + std::unordered_map> ActiveComputations; + MachinePassInstrumentation *Instrumentation = nullptr; + + friend class MachinePassManager; + friend class CompilationUnitPassManager; + friend Expected 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 [[nodiscard]] static AnalysisID id() noexcept { + return PreservedAnalyses::analysisID(); + } + + template + [[nodiscard]] Expected + registerAnalysis(CompilationUnitAnalysisRegistration Registration = {}) { + using ResultT = typename AnalysisT::Result; + if (Registration.ID == nullptr) + Registration.ID = id(); + if (Registration.Name.empty()) { + if constexpr (requires { + { AnalysisT::name() } -> std::convertible_to; + }) { + Registration.Name = std::string(AnalysisT::name()); + } else { + Registration.Name = "unnamed-compilation-unit-analysis"; + } + } + + ErasedRunner Runner = + [](CompilationUnit &Unit, const TargetDescription &Target, + CompilationUnitAnalysisManager &Manager) -> Expected> { + auto Computed = AnalysisT::run(Unit, Target, Manager); + if (!Computed) + return std::unexpected(Computed.error()); + return std::shared_ptr(new ResultT(std::move(*Computed)), + [](void *Value) { delete static_cast(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; + }) { + return static_cast(Value)->invalidate(Unit, Preserved); + } + return true; + }; + return registerAnalysisImpl(std::move(Registration), std::move(Runner), std::move(Invalidator)); + } + + template + [[nodiscard]] Expected getResult(CompilationUnit &Unit, + const TargetDescription &Target) { + const AnalysisID Key = id(); + if (!isRegistered(Key)) { + auto Registered = registerAnalysis(); + if (!Registered) + return std::unexpected(Registered.error()); + } + auto Result = getResultImpl(Key, Unit, Target); + if (!Result) + return std::unexpected(Result.error()); + return static_cast(*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>( + CompilationUnit &, const TargetDescription &, CompilationUnitAnalysisManager &)>; + using ErasedInvalidator = + std::function; + + struct RegisteredAnalysis final { + CompilationUnitAnalysisRegistration Info; + ErasedRunner Runner; + ErasedInvalidator Invalidator; + }; + + struct CacheEntry final { + std::shared_ptr Value; + AnalysisID ID = nullptr; + }; + + [[nodiscard]] Expected + registerAnalysisImpl(CompilationUnitAnalysisRegistration Registration, ErasedRunner Runner, + ErasedInvalidator Invalidator); + [[nodiscard]] Expected getResultImpl(AnalysisID ID, CompilationUnit &Unit, + const TargetDescription &Target); + [[nodiscard]] Expected materializeDependencies(const RegisteredAnalysis &Registration, + CompilationUnit &Unit, + const TargetDescription &Target); + void setInstrumentation(MachinePassInstrumentation *NewInstrumentation) noexcept { + Instrumentation = NewInstrumentation; + } + + std::unordered_map Registry; + std::unordered_map> Cache; + std::unordered_map> 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 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 + 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; + using AfterCallback = + std::function; + using FailureCallback = + std::function; + using BeforeAnalysisCallback = std::function; + using AfterAnalysisCallback = + std::function; + using AnalysisFailureCallback = + std::function; + using IRPrintCallback = + std::function; + using ChangeCallback = + std::function; + using ActionFilter = + std::function; + + using BeforeUnitCallback = std::function; + using AfterUnitCallback = std::function; + using UnitFailureCallback = + std::function; + using BeforeUnitAnalysisCallback = std::function; + using AfterUnitAnalysisCallback = + std::function; + using UnitAnalysisFailureCallback = + std::function; + + 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 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 statistics() const; + void clearStatistics(); + +private: + struct BufferedEvents final { + const TargetDescription *Target = nullptr; + std::vector> Events; + }; + + [[nodiscard]] bool bufferFunctionEvent(const MachineFunction &Function, + std::function 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 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 Before; + std::vector After; + std::vector Failure; + std::vector BeforeAnalysis; + std::vector AfterAnalysis; + std::vector AnalysisFailure; + std::vector IRPrint; + std::vector Change; + ActionFilter Filter; + std::optional PerFunctionFuel; + std::unordered_map ConsumedFuel; + + std::vector BeforeUnit; + std::vector AfterUnit; + std::vector UnitFailure; + std::vector BeforeUnitAnalysis; + std::vector AfterUnitAnalysis; + std::vector UnitAnalysisFailure; + mutable std::unordered_map 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 addPass(std::unique_ptr Pass); + [[nodiscard]] Expected run(MachineFunction &Function, const TargetDescription &Target, + MachineAnalysisManager &Analyses, + MachinePassInstrumentation *Instrumentation = nullptr) const; + [[nodiscard]] Expected + 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 validateContract(const MachinePassContract &Contract) const; + + MachinePassManagerOptions Options; + std::vector> 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 addPass(std::unique_ptr Pass); + [[nodiscard]] Expected run(CompilationUnit &Unit, const TargetDescription &Target, + CompilationUnitAnalysisManager &UnitAnalyses, + MachineAnalysisManager &FunctionAnalyses, + MachinePassInstrumentation *Instrumentation = nullptr) const; + +private: + CompilationUnitPassManagerOptions Options; + std::vector> 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 Flags) noexcept; + + [[nodiscard]] constexpr bool has(ABIValueFlag Flag) const noexcept { + const auto Index = static_cast(Flag); + return Index < static_cast(ABIValueFlag::Count) && + (Bits & (std::uint8_t{1} << Index)) != 0; + } + + constexpr void set(ABIValueFlag Flag) noexcept { + const auto Index = static_cast(Flag); + if (Index < static_cast(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 globalSymbol(std::string Name, + std::uint32_t TargetFlags = 0); + [[nodiscard]] static Expected externalSymbol(std::string Name, + std::uint32_t TargetFlags = 0); + [[nodiscard]] static Expected 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; + + 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 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 Arguments; + std::size_t FixedArgumentCount = 0; + bool IsVariadic = false; +}; + +struct CallLoweringRequest final { + CallingConventionID Convention; + MachineCallTarget Callee; + std::vector Arguments; + std::vector Results; + std::size_t FixedArgumentCount = 0; + std::uint64_t CallSiteID = 0; + bool IsVariadic = false; + TailCallKind TailKind = TailCallKind::NotTail; + std::optional TailContext; +}; + +struct ReturnLoweringRequest final { + CallingConventionID Convention; + std::vector 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 Flags) noexcept; + + [[nodiscard]] constexpr bool has(CCAssignmentFlag Flag) const noexcept { + const auto Index = static_cast(Flag); + return Index < static_cast(CCAssignmentFlag::Count) && + (Bits & (std::uint8_t{1} << Index)) != 0; + } + + constexpr void set(CCAssignmentFlag Flag) noexcept { + const auto Index = static_cast(Flag); + if (Index < static_cast(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 LocationRegister; + std::optional 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 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 ArgumentAssignments; + std::vector ReturnAssignments; + StackArgumentArea StackArguments; + CallFrameRequirements CallFrame; + VarArgLoweringState VarArgs; + std::vector ByValCopies; + std::shared_ptr PreservedMask; + std::optional Callee; + std::uint64_t CallSiteID = 0; + TailCallKind TailDecision = TailCallKind::NotTail; + std::string TailRejectionReason; +}; + +class CallLoweringPlan final { +public: + [[nodiscard]] static Expected 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 argumentAssignments() const noexcept { + return Description.ArgumentAssignments; + } + + [[nodiscard]] std::span 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 byValCopies() const noexcept { + return Description.ByValCopies; + } + + [[nodiscard]] const std::shared_ptr &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 lowerFormalArguments(MachineIRBuilder &Builder, + const FormalArgumentRequest &Request) const; + [[nodiscard]] Expected lowerCall(MachineIRBuilder &Builder, + const CallLoweringRequest &Request) const; + [[nodiscard]] Expected lowerReturn(MachineIRBuilder &Builder, + const ReturnLoweringRequest &Request) const; + + [[nodiscard]] virtual Expected + planFormalArguments(const FormalArgumentRequest &Request) const = 0; + [[nodiscard]] virtual Expected + planCall(const CallLoweringRequest &Request) const = 0; + [[nodiscard]] virtual Expected + planReturn(const ReturnLoweringRequest &Request) const = 0; + [[nodiscard]] virtual Expected emitPlan(MachineIRBuilder &Builder, + const CallLoweringPlan &Plan) const = 0; +}; + +} // namespace rcc + +#endif // RCC_CODEGEN_TARGETCALLLOWERING_H diff --git a/backend/include/rcc/Target/RISCV/RISCVCallLowering.h b/backend/include/rcc/Target/RISCV/RISCVCallLowering.h new file mode 100644 index 0000000..445c922 --- /dev/null +++ b/backend/include/rcc/Target/RISCV/RISCVCallLowering.h @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef RCC_TARGET_RISCV_RISCVCALLLOWERING_H +#define RCC_TARGET_RISCV_RISCVCALLLOWERING_H + +#include "rcc/CodeGen/TargetCallLowering.h" +#include "rcc/Target/RISCV/RISCVInstructions.h" + +#include + +namespace rcc::riscv { + +enum class CallTargetFlag : std::uint32_t { + DirectCall = 1U << 0U, +}; + +enum class CallStackObjectFlag : std::uint64_t { + IncomingArgument = 1ULL << 0U, + OutgoingArgument = 1ULL << 1U, + ByValCopy = 1ULL << 2U, + VarArgSaveArea = 1ULL << 3U, + VarArgAlignmentPadding = 1ULL << 4U, +}; + +enum class CallValueTransform : std::uint8_t { + Full, + AnyExtend, + SignExtend, + ZeroExtend, + Truncate, + Bitcast, +}; + +[[nodiscard]] constexpr CallingConventionID +callingConventionID(CallingConvention Convention) noexcept { + return CallingConventionID::fromValue(static_cast(Convention)); +} + +[[nodiscard]] const TargetCallLowering &callLowering() noexcept; + +} // namespace rcc::riscv + +#endif // RCC_TARGET_RISCV_RISCVCALLLOWERING_H -- cgit v1.2.3