vicis/codegen/isa/x86_64/lower/
load.rs1use 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 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 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}