Skip to content

Commit 7bdeda8

Browse files
authored
Merge pull request #8494 from mattnite/cbe-wrapping-addition
Wrapping add/sub for the C backend
2 parents 62d27fc + 9dbe684 commit 7bdeda8

File tree

3 files changed

+394
-8
lines changed

3 files changed

+394
-8
lines changed

src/codegen/c.zig

Lines changed: 115 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -846,18 +846,15 @@ pub fn genBody(o: *Object, body: ir.Body) error{ AnalysisFail, OutOfMemory }!voi
846846
// TODO use a different strategy for add that communicates to the optimizer
847847
// that wrapping is UB.
848848
.add => try genBinOp(o, inst.castTag(.add).?, " + "),
849-
// TODO make this do wrapping arithmetic for signed ints
850-
.addwrap => try genBinOp(o, inst.castTag(.add).?, " + "),
849+
.addwrap => try genWrapOp(o, inst.castTag(.addwrap).?, " + ", "addw_"),
851850
// TODO use a different strategy for sub that communicates to the optimizer
852851
// that wrapping is UB.
853852
.sub => try genBinOp(o, inst.castTag(.sub).?, " - "),
854-
// TODO make this do wrapping arithmetic for signed ints
855-
.subwrap => try genBinOp(o, inst.castTag(.sub).?, " - "),
853+
.subwrap => try genWrapOp(o, inst.castTag(.subwrap).?, " - ", "subw_"),
856854
// TODO use a different strategy for mul that communicates to the optimizer
857855
// that wrapping is UB.
858856
.mul => try genBinOp(o, inst.castTag(.sub).?, " * "),
859-
// TODO make this do wrapping multiplication for signed ints
860-
.mulwrap => try genBinOp(o, inst.castTag(.sub).?, " * "),
857+
.mulwrap => try genWrapOp(o, inst.castTag(.mulwrap).?, " * ", "mulw_"),
861858
// TODO use a different strategy for div that communicates to the optimizer
862859
// that wrapping is UB.
863860
.div => try genBinOp(o, inst.castTag(.div).?, " / "),
@@ -1042,7 +1039,117 @@ fn genStore(o: *Object, inst: *Inst.BinOp) !CValue {
10421039
return CValue.none;
10431040
}
10441041

1045-
fn genBinOp(o: *Object, inst: *Inst.BinOp, operator: []const u8) !CValue {
1042+
fn genWrapOp(o: *Object, inst: *Inst.BinOp, str_op: [*:0]const u8, fn_op: [*:0]const u8) !CValue {
1043+
if (inst.base.isUnused())
1044+
return CValue.none;
1045+
1046+
const int_info = inst.base.ty.intInfo(o.dg.module.getTarget());
1047+
const bits = int_info.bits;
1048+
1049+
// if it's an unsigned int with non-arbitrary bit size then we can just add
1050+
if (int_info.signedness == .unsigned) {
1051+
const ok_bits = switch (bits) {
1052+
8, 16, 32, 64, 128 => true,
1053+
else => false,
1054+
};
1055+
if (ok_bits or inst.base.ty.tag() != .int_unsigned) {
1056+
return try genBinOp(o, inst, str_op);
1057+
}
1058+
}
1059+
1060+
if (bits > 64) {
1061+
return o.dg.fail(.{ .node_offset = 0 }, "TODO: C backend: genWrapOp for large integers", .{});
1062+
}
1063+
1064+
var min_buf: [80]u8 = undefined;
1065+
const min = switch (int_info.signedness) {
1066+
.unsigned => "0",
1067+
else => switch (inst.base.ty.tag()) {
1068+
.c_short => "SHRT_MIN",
1069+
.c_int => "INT_MIN",
1070+
.c_long => "LONG_MIN",
1071+
.c_longlong => "LLONG_MIN",
1072+
.isize => "INTPTR_MIN",
1073+
else => blk: {
1074+
const val = -1 * std.math.pow(i64, 2, @intCast(i64, bits - 1));
1075+
break :blk std.fmt.bufPrint(&min_buf, "{d}", .{val}) catch |err| switch (err) {
1076+
error.NoSpaceLeft => unreachable,
1077+
else => |e| return e,
1078+
};
1079+
},
1080+
},
1081+
};
1082+
1083+
var max_buf: [80]u8 = undefined;
1084+
const max = switch (inst.base.ty.tag()) {
1085+
.c_short => "SHRT_MAX",
1086+
.c_ushort => "USHRT_MAX",
1087+
.c_int => "INT_MAX",
1088+
.c_uint => "UINT_MAX",
1089+
.c_long => "LONG_MAX",
1090+
.c_ulong => "ULONG_MAX",
1091+
.c_longlong => "LLONG_MAX",
1092+
.c_ulonglong => "ULLONG_MAX",
1093+
.isize => "INTPTR_MAX",
1094+
.usize => "UINTPTR_MAX",
1095+
else => blk: {
1096+
const pow_bits = switch (int_info.signedness) {
1097+
.signed => bits - 1,
1098+
.unsigned => bits,
1099+
};
1100+
const val = std.math.pow(u64, 2, pow_bits) - 1;
1101+
break :blk std.fmt.bufPrint(&max_buf, "{}", .{val}) catch |err| switch (err) {
1102+
error.NoSpaceLeft => unreachable,
1103+
else => |e| return e,
1104+
};
1105+
},
1106+
};
1107+
1108+
const lhs = try o.resolveInst(inst.lhs);
1109+
const rhs = try o.resolveInst(inst.rhs);
1110+
const w = o.writer();
1111+
1112+
const ret = try o.allocLocal(inst.base.ty, .Mut);
1113+
try w.print(" = zig_{s}", .{fn_op});
1114+
1115+
switch (inst.base.ty.tag()) {
1116+
.isize => try w.writeAll("isize"),
1117+
.c_short => try w.writeAll("short"),
1118+
.c_int => try w.writeAll("int"),
1119+
.c_long => try w.writeAll("long"),
1120+
.c_longlong => try w.writeAll("longlong"),
1121+
else => {
1122+
const prefix_byte: u8 = switch (int_info.signedness) {
1123+
.signed => 'i',
1124+
.unsigned => 'u',
1125+
};
1126+
for ([_]u8{ 8, 16, 32, 64 }) |nbits| {
1127+
if (bits <= nbits) {
1128+
try w.print("{c}{d}", .{ prefix_byte, nbits });
1129+
break;
1130+
}
1131+
} else {
1132+
unreachable;
1133+
}
1134+
},
1135+
}
1136+
1137+
try w.writeByte('(');
1138+
try o.writeCValue(w, lhs);
1139+
try w.writeAll(", ");
1140+
try o.writeCValue(w, rhs);
1141+
1142+
if (int_info.signedness == .signed) {
1143+
try w.print(", {s}", .{min});
1144+
}
1145+
1146+
try w.print(", {s});", .{max});
1147+
try o.indent_writer.insertNewline();
1148+
1149+
return ret;
1150+
}
1151+
1152+
fn genBinOp(o: *Object, inst: *Inst.BinOp, operator: [*:0]const u8) !CValue {
10461153
if (inst.base.isUnused())
10471154
return CValue.none;
10481155

@@ -1054,7 +1161,7 @@ fn genBinOp(o: *Object, inst: *Inst.BinOp, operator: []const u8) !CValue {
10541161

10551162
try writer.writeAll(" = ");
10561163
try o.writeCValue(writer, lhs);
1057-
try writer.writeAll(operator);
1164+
try writer.print("{s}", .{operator});
10581165
try o.writeCValue(writer, rhs);
10591166
try writer.writeAll(";\n");
10601167

src/link/C/zig.h

Lines changed: 229 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,236 @@
6262

6363
#include <stdint.h>
6464
#include <stddef.h>
65+
#include <limits.h>
6566
#define int128_t __int128
6667
#define uint128_t unsigned __int128
6768
ZIG_EXTERN_C void *memcpy (void *ZIG_RESTRICT, const void *ZIG_RESTRICT, size_t);
6869

70+
static inline uint8_t zig_addw_u8(uint8_t lhs, uint8_t rhs, uint8_t max) {
71+
uint8_t thresh = max - rhs;
72+
if (lhs > thresh) {
73+
return lhs - thresh - 1;
74+
} else {
75+
return lhs + rhs;
76+
}
77+
}
78+
79+
static inline int8_t zig_addw_i8(int8_t lhs, int8_t rhs, int8_t min, int8_t max) {
80+
if ((lhs > 0) && (rhs > 0)) {
81+
int8_t thresh = max - rhs;
82+
if (lhs > thresh) {
83+
return min + lhs - thresh - 1;
84+
}
85+
} else if ((lhs < 0) && (rhs < 0)) {
86+
int8_t thresh = min - rhs;
87+
if (lhs < thresh) {
88+
return max + lhs - thresh + 1;
89+
}
90+
}
91+
return lhs + rhs;
92+
}
93+
94+
static inline uint16_t zig_addw_u16(uint16_t lhs, uint16_t rhs, uint16_t max) {
95+
uint16_t thresh = max - rhs;
96+
if (lhs > thresh) {
97+
return lhs - thresh - 1;
98+
} else {
99+
return lhs + rhs;
100+
}
101+
}
102+
103+
static inline int16_t zig_addw_i16(int16_t lhs, int16_t rhs, int16_t min, int16_t max) {
104+
if ((lhs > 0) && (rhs > 0)) {
105+
int16_t thresh = max - rhs;
106+
if (lhs > thresh) {
107+
return min + lhs - thresh - 1;
108+
}
109+
} else if ((lhs < 0) && (rhs < 0)) {
110+
int16_t thresh = min - rhs;
111+
if (lhs < thresh) {
112+
return max + lhs - thresh + 1;
113+
}
114+
}
115+
return lhs + rhs;
116+
}
117+
118+
static inline uint32_t zig_addw_u32(uint32_t lhs, uint32_t rhs, uint32_t max) {
119+
uint32_t thresh = max - rhs;
120+
if (lhs > thresh) {
121+
return lhs - thresh - 1;
122+
} else {
123+
return lhs + rhs;
124+
}
125+
}
126+
127+
static inline int32_t zig_addw_i32(int32_t lhs, int32_t rhs, int32_t min, int32_t max) {
128+
if ((lhs > 0) && (rhs > 0)) {
129+
int32_t thresh = max - rhs;
130+
if (lhs > thresh) {
131+
return min + lhs - thresh - 1;
132+
}
133+
} else if ((lhs < 0) && (rhs < 0)) {
134+
int32_t thresh = min - rhs;
135+
if (lhs < thresh) {
136+
return max + lhs - thresh + 1;
137+
}
138+
}
139+
return lhs + rhs;
140+
}
141+
142+
static inline uint64_t zig_addw_u64(uint64_t lhs, uint64_t rhs, uint64_t max) {
143+
uint64_t thresh = max - rhs;
144+
if (lhs > thresh) {
145+
return lhs - thresh - 1;
146+
} else {
147+
return lhs + rhs;
148+
}
149+
}
150+
151+
static inline int64_t zig_addw_i64(int64_t lhs, int64_t rhs, int64_t min, int64_t max) {
152+
if ((lhs > 0) && (rhs > 0)) {
153+
int64_t thresh = max - rhs;
154+
if (lhs > thresh) {
155+
return min + lhs - thresh - 1;
156+
}
157+
} else if ((lhs < 0) && (rhs < 0)) {
158+
int64_t thresh = min - rhs;
159+
if (lhs < thresh) {
160+
return max + lhs - thresh + 1;
161+
}
162+
}
163+
return lhs + rhs;
164+
}
165+
166+
static inline intptr_t zig_addw_isize(intptr_t lhs, intptr_t rhs, intptr_t min, intptr_t max) {
167+
return (intptr_t)(((uintptr_t)lhs) + ((uintptr_t)rhs));
168+
}
169+
170+
static inline short zig_addw_short(short lhs, short rhs, short min, short max) {
171+
return (short)(((unsigned short)lhs) + ((unsigned short)rhs));
172+
}
173+
174+
static inline int zig_addw_int(int lhs, int rhs, int min, int max) {
175+
return (int)(((unsigned)lhs) + ((unsigned)rhs));
176+
}
177+
178+
static inline long zig_addw_long(long lhs, long rhs, long min, long max) {
179+
return (long)(((unsigned long)lhs) + ((unsigned long)rhs));
180+
}
181+
182+
static inline long long zig_addw_longlong(long long lhs, long long rhs, long long min, long long max) {
183+
return (long long)(((unsigned long long)lhs) + ((unsigned long long)rhs));
184+
}
185+
186+
static inline uint8_t zig_subw_u8(uint8_t lhs, uint8_t rhs, uint8_t max) {
187+
if (lhs < rhs) {
188+
return max - rhs - lhs + 1;
189+
} else {
190+
return lhs - rhs;
191+
}
192+
}
193+
194+
static inline int8_t zig_subw_i8(int8_t lhs, int8_t rhs, int8_t min, int8_t max) {
195+
if ((lhs > 0) && (rhs < 0)) {
196+
int8_t thresh = lhs - max;
197+
if (rhs < thresh) {
198+
return min + (thresh - rhs - 1);
199+
}
200+
} else if ((lhs < 0) && (rhs > 0)) {
201+
int8_t thresh = lhs - min;
202+
if (rhs > thresh) {
203+
return max - (rhs - thresh - 1);
204+
}
205+
}
206+
return lhs - rhs;
207+
}
208+
209+
static inline uint16_t zig_subw_u16(uint16_t lhs, uint16_t rhs, uint16_t max) {
210+
if (lhs < rhs) {
211+
return max - rhs - lhs + 1;
212+
} else {
213+
return lhs - rhs;
214+
}
215+
}
216+
217+
static inline int16_t zig_subw_i16(int16_t lhs, int16_t rhs, int16_t min, int16_t max) {
218+
if ((lhs > 0) && (rhs < 0)) {
219+
int16_t thresh = lhs - max;
220+
if (rhs < thresh) {
221+
return min + (thresh - rhs - 1);
222+
}
223+
} else if ((lhs < 0) && (rhs > 0)) {
224+
int16_t thresh = lhs - min;
225+
if (rhs > thresh) {
226+
return max - (rhs - thresh - 1);
227+
}
228+
}
229+
return lhs - rhs;
230+
}
231+
232+
static inline uint32_t zig_subw_u32(uint32_t lhs, uint32_t rhs, uint32_t max) {
233+
if (lhs < rhs) {
234+
return max - rhs - lhs + 1;
235+
} else {
236+
return lhs - rhs;
237+
}
238+
}
239+
240+
static inline int32_t zig_subw_i32(int32_t lhs, int32_t rhs, int32_t min, int32_t max) {
241+
if ((lhs > 0) && (rhs < 0)) {
242+
int32_t thresh = lhs - max;
243+
if (rhs < thresh) {
244+
return min + (thresh - rhs - 1);
245+
}
246+
} else if ((lhs < 0) && (rhs > 0)) {
247+
int32_t thresh = lhs - min;
248+
if (rhs > thresh) {
249+
return max - (rhs - thresh - 1);
250+
}
251+
}
252+
return lhs - rhs;
253+
}
254+
255+
static inline uint64_t zig_subw_u64(uint64_t lhs, uint64_t rhs, uint64_t max) {
256+
if (lhs < rhs) {
257+
return max - rhs - lhs + 1;
258+
} else {
259+
return lhs - rhs;
260+
}
261+
}
262+
263+
static inline int64_t zig_subw_i64(int64_t lhs, int64_t rhs, int64_t min, int64_t max) {
264+
if ((lhs > 0) && (rhs < 0)) {
265+
int64_t thresh = lhs - max;
266+
if (rhs < thresh) {
267+
return min + (thresh - rhs - 1);
268+
}
269+
} else if ((lhs < 0) && (rhs > 0)) {
270+
int64_t thresh = lhs - min;
271+
if (rhs > thresh) {
272+
return max - (rhs - thresh - 1);
273+
}
274+
}
275+
return lhs - rhs;
276+
}
277+
278+
static inline intptr_t zig_subw_isize(intptr_t lhs, intptr_t rhs, intptr_t min, intptr_t max) {
279+
return (intptr_t)(((uintptr_t)lhs) - ((uintptr_t)rhs));
280+
}
281+
282+
static inline short zig_subw_short(short lhs, short rhs, short min, short max) {
283+
return (short)(((unsigned short)lhs) - ((unsigned short)rhs));
284+
}
285+
286+
static inline int zig_subw_int(int lhs, int rhs, int min, int max) {
287+
return (int)(((unsigned)lhs) - ((unsigned)rhs));
288+
}
289+
290+
static inline long zig_subw_long(long lhs, long rhs, long min, long max) {
291+
return (long)(((unsigned long)lhs) - ((unsigned long)rhs));
292+
}
293+
294+
static inline long long zig_subw_longlong(long long lhs, long long rhs, long long min, long long max) {
295+
return (long long)(((unsigned long long)lhs) - ((unsigned long long)rhs));
296+
}
297+

0 commit comments

Comments
 (0)