llvm_scratch/core/instruction/
inst.rs

1use std::fmt;
2use std::fmt::Formatter;
3
4use id_arena::Id;
5
6use crate::core::{
7    function::{FunctionType, ParameterSet, ReturnType},
8    llvm_string::LLVMString,
9    llvm_type, llvm_value,
10};
11
12pub type InstructionId = Id<Instruction>;
13
14/// An representation of LLVMInstruction.
15/// LLVMInstruction を表す構造体
16#[derive(Eq, PartialEq, PartialOrd, Ord, Hash)]
17pub struct Instruction {
18    pub kind: InstKind,
19    dst_value: Option<llvm_value::LLVMValue>,
20}
21
22impl Instruction {
23    pub fn new(inst_kind: InstKind, dst_value: Option<llvm_value::LLVMValue>) -> Self {
24        Self {
25            kind: inst_kind,
26            dst_value,
27        }
28    }
29
30    pub fn is_terminator(&self) -> bool {
31        match &self.kind {
32            InstKind::RETVOID => true,
33            _ => false,
34        }
35    }
36}
37
38impl fmt::Display for Instruction {
39    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
40        match &self.kind {
41            InstKind::ALLOCA(alloc_type, elements_opt, align_opt, addr_opt) => {
42                if let Some(dst) = &self.dst_value {
43                    write!(f, "{} = ", dst)?;
44                }
45                write!(f, "alloca {}", alloc_type)?;
46
47                if let Some(elements) = elements_opt {
48                    write!(f, ", {} {}", elements.0, elements.1)?;
49                }
50
51                if let Some(align) = align_opt {
52                    write!(f, ", align {}", align)?;
53                }
54
55                if let Some(addr) = addr_opt {
56                    write!(f, ", addrspace({})", addr)?;
57                }
58            }
59            InstKind::CALL(tail_opt, flags_opt, ret_ty_res, callee_name, args) => {
60                if let Some(dst) = &self.dst_value {
61                    write!(f, "{} = ", dst)?;
62                }
63
64                if let Some(tail) = tail_opt {
65                    write!(f, "{} ", tail)?;
66                }
67
68                write!(f, "call ")?;
69
70                if let Some(flag) = flags_opt {
71                    write!(f, "{} ", flag)?;
72                }
73
74                match ret_ty_res {
75                    Ok(ret_ty) => {
76                        write!(f, "{} ", ret_ty)?;
77                    }
78                    Err(fn_ty) => {
79                        write!(f, "{} ", fn_ty)?;
80                    }
81                }
82
83                write!(f, "@{}{}", callee_name, args)?;
84            }
85            InstKind::GETELEMENTPTR(inbounds, res_ty, src_value, indexes) => {
86                if let Some(dst) = &self.dst_value {
87                    write!(f, "{} = ", dst)?;
88                }
89
90                write!(f, "getelementptr ")?;
91
92                if *inbounds {
93                    write!(f, "inbounds ")?;
94                }
95
96                write!(f, "{}, {}* {}, ", res_ty, res_ty, src_value)?;
97
98                for (i, (idx_ty, idx_v)) in indexes.iter().enumerate() {
99                    if i == indexes.len() - 1 {
100                        write!(f, "{} {}", idx_ty, idx_v)?;
101                    } else {
102                        write!(f, "{} {}, ", idx_ty, idx_v)?;
103                    }
104                }
105            }
106            InstKind::RETVOID => {
107                write!(f, "ret void")?;
108            }
109        }
110        Ok(())
111    }
112}
113
114type NumElements = u32;
115type Alignment = u32;
116type AddrSpace = u32;
117type Inbounds = bool;
118
119/// LLVMInstruction の種類
120#[derive(Eq, PartialEq, PartialOrd, Ord, Hash)]
121pub enum InstKind {
122    ALLOCA(
123        llvm_type::LLVMType,
124        Option<(llvm_type::LLVMType, NumElements)>,
125        Option<Alignment>,
126        Option<AddrSpace>,
127    ),
128    CALL(
129        Option<TailMarker>,
130        Option<FastMathFlags>,
131        Result<ReturnType, FunctionType>,
132        LLVMString,
133        ParameterSet,
134    ),
135    GETELEMENTPTR(
136        Inbounds,
137        llvm_type::LLVMType,
138        llvm_value::LLVMValue,
139        Vec<(llvm_type::LLVMType, llvm_value::LLVMValue)>,
140    ),
141    RETVOID,
142}
143
144#[derive(Eq, PartialEq, PartialOrd, Ord, Hash)]
145pub enum TailMarker {
146    TAIL,
147    MUSTTAIL,
148    NOTAIL,
149}
150
151impl fmt::Display for TailMarker {
152    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
153        let tail_str = match self {
154            Self::TAIL => "tail",
155            Self::MUSTTAIL => "musttail",
156            Self::NOTAIL => "notail",
157        };
158
159        write!(f, "{}", tail_str)
160    }
161}
162
163#[derive(Eq, PartialEq, PartialOrd, Ord, Hash)]
164pub enum FastMathFlags {
165    NNAN,
166    NINF,
167    NSZ,
168    ARCP,
169    CONTRACT,
170    AFN,
171    REASSOC,
172    FAST,
173}
174
175impl fmt::Display for FastMathFlags {
176    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
177        let flag_str = match self {
178            Self::NNAN => "nnan",
179            Self::NINF => "ninf",
180            Self::NSZ => "nsz",
181            Self::ARCP => "arcp",
182            Self::CONTRACT => "contract",
183            Self::AFN => "afn",
184            Self::REASSOC => "reassoc",
185            Self::FAST => "fast",
186        };
187
188        write!(f, "{}", flag_str)
189    }
190}
191
192#[derive(Eq, PartialEq, PartialOrd, Ord, Hash)]
193pub enum Linkage {
194    PRIVATE,
195    INTERNAL,
196    EXTERNAL,
197}
198
199impl fmt::Display for Linkage {
200    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
201        let linkage_str = match self {
202            Self::PRIVATE => "private",
203            Self::INTERNAL => "internal",
204            Self::EXTERNAL => "external",
205        };
206
207        write!(f, "{}", linkage_str)
208    }
209}