aboutsummaryrefslogtreecommitdiff
path: root/backend/include
diff options
context:
space:
mode:
authorRichard-Qin-X <richard.qin.001@gmail.com>2026-08-07 22:06:28 +0800
committerRichard-Qin-X <richard.qin.001@gmail.com>2026-08-07 22:06:28 +0800
commitf99ef4322a7a2c09380fff61f88ab9440f05a92c (patch)
tree69538d9ac3acb4a4a680dbce143f39c7b576035c /backend/include
parent3e15bfd7b075209ec3b65d30d0611e060f6fbb77 (diff)
downloadrcc-project-f99ef4322a7a2c09380fff61f88ab9440f05a92c.tar.gz
rcc-project-f99ef4322a7a2c09380fff61f88ab9440f05a92c.tar.xz
[CodeGen] Complete machine pass and ABI lowering infrastructure
Diffstat (limited to 'backend/include')
-rw-r--r--backend/include/rcc/CodeGen/GenericOpcode.def336
-rw-r--r--backend/include/rcc/CodeGen/GenericOpcodes.h68
-rw-r--r--backend/include/rcc/CodeGen/MachineAnalyses.h244
-rw-r--r--backend/include/rcc/CodeGen/MachineIRBuilder.h10
-rw-r--r--backend/include/rcc/CodeGen/MachineIRTypes.h3
-rw-r--r--backend/include/rcc/CodeGen/MachinePass.h655
-rw-r--r--backend/include/rcc/CodeGen/TargetCallLowering.h404
-rw-r--r--backend/include/rcc/Target/RISCV/RISCVCallLowering.h43
8 files changed, 1763 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
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 <cstdint>
+
+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<std::uint32_t>(Convention));
+}
+
+[[nodiscard]] const TargetCallLowering &callLowering() noexcept;
+
+} // namespace rcc::riscv
+
+#endif // RCC_TARGET_RISCV_RISCVCALLLOWERING_H