Skip to main content

vicis/codegen/isa/x86_64/lower/
load.rs

1use super::{get_or_generate_inst_output, new_empty_inst_output};
2use crate::codegen::{
3    function::instruction::Instruction as MachInstruction,
4    isa::x86_64::{
5        instruction::{InstructionData, Opcode, Operand as MOperand, OperandData},
6        X86_64,
7    },
8    isa::TargetIsa,
9    lower::{LoweringContext, LoweringError},
10};
11use crate::ir::{
12    function::instruction::{InstructionId, Opcode as IrOpcode},
13    types::{Type, TypeId},
14    value::{ConstantData, ConstantInt, Value, ValueId},
15};
16use anyhow::Result;
17
18pub fn lower_load(
19    ctx: &mut LoweringContext<X86_64>,
20    id: InstructionId,
21    tys: &[TypeId],
22    addr: ValueId,
23    _align: u32,
24) -> Result<()> {
25    let mut slot = None;
26
27    if let Value::Instruction(gep_id) = &ctx.ir_data.values[addr] {
28        if let Some(slot_id) = ctx.inst_id_to_slot_id.get(gep_id) {
29            slot = Some(*slot_id);
30        } else {
31            let opcode = ctx.ir_data.instructions[*gep_id].opcode;
32            if opcode == IrOpcode::GetElementPtr {
33                return lower_load_gep(ctx, id, tys, *gep_id, _align);
34            }
35        }
36    } else {
37        panic!()
38    }
39
40    if let Some(slot) = slot {
41        let src_ty = tys[0];
42        if matches!(&*ctx.types.get(src_ty), Type::Int(32)) {
43            let output = new_empty_inst_output(ctx, tys[0], id);
44            ctx.inst_seq.push(MachInstruction::new(InstructionData {
45                opcode: Opcode::MOVrm32,
46                operands: vec![
47                    MOperand::output(output.into()),
48                    MOperand::new(OperandData::MemStart),
49                    MOperand::new(OperandData::Slot(slot)),
50                    MOperand::new(OperandData::None),
51                    MOperand::input(OperandData::None),
52                    MOperand::input(OperandData::None),
53                    MOperand::new(OperandData::None),
54                ],
55            }));
56            return Ok(());
57        }
58    }
59
60    Err(LoweringError::Todo.into())
61}
62
63fn lower_load_gep(
64    ctx: &mut LoweringContext<X86_64>,
65    id: InstructionId,
66    tys: &[TypeId],
67    gep_id: InstructionId,
68    _align: u32,
69) -> Result<()> {
70    use {Constant as Const, ConstantData::Int, ConstantInt::Int64, Value::Constant};
71
72    let gep = &ctx.ir_data.instructions[gep_id];
73
74    let gep_args: Vec<&Value> = gep
75        .operand
76        .args()
77        .into_iter()
78        .map(|&arg| &ctx.ir_data.values[arg])
79        .collect();
80
81    let mem;
82
83    match &gep_args[..] {
84        [Value::Instruction(base_ptr), Const(Int(Int64(idx0))), Const(Int(Int64(idx1)))] => {
85            let base_ptr = ctx.inst_id_to_slot_id[base_ptr];
86            let base_ty = gep.operand.types()[0];
87            let offset = idx0 * X86_64::type_size(ctx.types, base_ty) as i64
88                + idx1
89                    * X86_64::type_size(ctx.types, ctx.types.get_element(base_ty).unwrap()) as i64;
90            // debug!(offset);
91
92            mem = vec![
93                MOperand::new(OperandData::MemStart),
94                MOperand::new(OperandData::Slot(base_ptr)),
95                MOperand::new(OperandData::Int32(offset as i32)),
96                MOperand::input(OperandData::None),
97                MOperand::input(OperandData::None),
98                MOperand::new(OperandData::None),
99            ];
100        }
101        [Value::Instruction(base_ptr), Const(Int(Int64(idx0))), Value::Instruction(idx1)] => {
102            let base_ptr = ctx.inst_id_to_slot_id[base_ptr];
103
104            let base_ty = gep.operand.types()[0];
105            let offset = idx0 * X86_64::type_size(ctx.types, base_ty) as i64;
106            // debug!(offset);
107
108            let idx1_ty = gep.operand.types()[3];
109            assert_eq!(*ctx.types.get(idx1_ty), Type::Int(64));
110            let idx1 = get_or_generate_inst_output(ctx, idx1_ty, *idx1)?;
111
112            assert!(X86_64::type_size(ctx.types, ctx.types.get_element(base_ty).unwrap()) == 4);
113
114            mem = vec![
115                MOperand::new(OperandData::MemStart),
116                MOperand::new(OperandData::Slot(base_ptr)),
117                MOperand::new(OperandData::Int32(offset as i32)),
118                MOperand::input(OperandData::None),
119                MOperand::input(OperandData::VReg(idx1)),
120                MOperand::new(OperandData::Int32(X86_64::type_size(
121                    ctx.types,
122                    ctx.types.get_element(base_ty).unwrap(),
123                ) as i32)),
124            ];
125        }
126        _ => return Err(LoweringError::Todo.into()),
127    }
128
129    let output = new_empty_inst_output(ctx, tys[0], id);
130
131    let src_ty = tys[0];
132    match &*ctx.types.get(src_ty) {
133        Type::Int(32) => {
134            ctx.inst_seq
135                .append(&mut vec![MachInstruction::new(InstructionData {
136                    opcode: Opcode::MOVrm32,
137                    operands: vec![MOperand::output(OperandData::VReg(output))]
138                        .into_iter()
139                        .chain(mem.into_iter())
140                        .collect(),
141                })]);
142        }
143        _ => return Err(LoweringError::Todo.into()),
144    }
145
146    Ok(())
147}