MCPcopy Create free account
hub / github.com/chc4/lineiform / adc

Function adc

tangle/src/oper.rs:123–219  ·  view source on GitHub ↗

Add with carry

(&mut self, left: JitTemp, right: JitTemp, carry: JitTemp)

Source from the content-addressed store, hash-verified

121
122 /// Add with carry
123 pub fn adc<const FLAG:bool>(&mut self, left: JitTemp, right: JitTemp, carry: JitTemp) -> JitTemp {
124 use JitTemp::*;
125 use Flags::*;
126 let flags = vec![OF, SF, ZF, AF, PF, CF];
127 match (left.clone(), right.clone(), carry.clone()) {
128 (Value(val_left, typ_left), Value(val_right, _), Flag(val_carry)) => {
129 let (res, flag) = self.builder.ins().iadd_carry(val_left, val_right, val_carry);
130 self.context.set_flags(flags, (val_left, val_right, flag));
131 Value(res, typ_left)
132 },
133 (_, _, carry) if carry.is_const() => {
134 // basically, this sucks a lot:
135 // iadd_carry is broken on cranelift (#2860), so we work around
136 // it by lowering to a normal iadd_cout in the CF=false case,
137 // and to two iadd_cout's in the CF=true case (and then have to
138 // fixup our carry flag so the spliced +1 doesn't break).
139 let carry = carry.into_usize(self.builder).unwrap();
140 if carry == 0 {
141 return self.add::<FLAG>(left, right);
142 } else {
143 let left_plus_one = self.add::<FLAG>(left, Const8(1));
144 // track if the +1 overflowed
145 let carried = self.context.check_flag(Flags::CF, true, self.builder);
146
147 let res = self.add::<FLAG>(left_plus_one, right);
148 if(FLAG) {
149 // if the +1 definitely carried, we know that carry has to
150 // be set.
151 println!("carried = {:?}", carried);
152 if let JitTemp::Const64(1) = carried {
153 self.context.flags[Flags::CF as usize] = JitFlag::Known(1 << Flags::CF as usize);
154 } else if let JitTemp::Const64(0) = carried {
155 ();
156 } else if let JitTemp::Value(val, typ) = carried {
157 unimplemented!("double check this");
158 // but if we don't know, then we have to OR it with
159 // the other carry flag (which sucks!)
160 let other_carried = self.context.check_flag(Flags::CF, true, self.builder);
161 let maybe_carried = self.bor(other_carried, carried);
162 self.context.set_flags(vec![Flags::CF],
163 (left_plus_one.into_ssa(typ, self.builder),
164 right.into_ssa(typ, self.builder),
165 maybe_carried.into_ssa(typ, self.builder)));
166 } else {
167 unimplemented!();
168 }
169 }
170 return res;
171 }
172 },
173 (left @ Value(_, _), right @ _, carry @ _) |
174 (left @ _, right @ Value(_, _), carry @ _) |
175 (left @ _, right @ _, carry @ Flag(_)) => {
176 let typ = Type::int((left.width() * 8) as u16).unwrap();
177 let _left = left.into_ssa(typ, self.builder);
178 let _right = right.zero_extend(self.builder, left.width()).into_ssa(typ, self.builder);
179 let mut _carry = carry.into_ssa(types::IFLAGS, self.builder);
180 let (res, flag) = self.builder.ins().iadd_ifcarry(_left, _right, _carry);

Callers

nothing calls this directly

Calls 1

cloneMethod · 0.80

Tested by

no test coverage detected