authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2020-12-23 12:17:40+02:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2020-12-23 12:17:40+02:00
logce7dcf2294297a6037da77b146023311acf8862b
treefc6648dd0ea42b2201d17e52d10c7d755177462a
parent53a8e7320510ab64616240ea70ea2e94fcfc02c7
parent45a88be573dee8e61490f7d864cc53720981eaff
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #7507 from joachimschmidt557/stage2-arm

stage2 ARM: implement basic binary bitwise operations

5 files changed, 240 insertions(+), 6 deletions(-)

src/codegen.zig+36-3
...@@ -764,6 +764,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -764,6 +764,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
764 .arg => return self.genArg(inst.castTag(.arg).?),764 .arg => return self.genArg(inst.castTag(.arg).?),
765 .assembly => return self.genAsm(inst.castTag(.assembly).?),765 .assembly => return self.genAsm(inst.castTag(.assembly).?),
766 .bitcast => return self.genBitCast(inst.castTag(.bitcast).?),766 .bitcast => return self.genBitCast(inst.castTag(.bitcast).?),
767 .bitand => return self.genBitAnd(inst.castTag(.bitand).?),
768 .bitor => return self.genBitOr(inst.castTag(.bitor).?),
767 .block => return self.genBlock(inst.castTag(.block).?),769 .block => return self.genBlock(inst.castTag(.block).?),
768 .br => return self.genBr(inst.castTag(.br).?),770 .br => return self.genBr(inst.castTag(.br).?),
769 .breakpoint => return self.genBreakpoint(inst.src),771 .breakpoint => return self.genBreakpoint(inst.src),
...@@ -799,6 +801,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -799,6 +801,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
799 .unwrap_optional => return self.genUnwrapOptional(inst.castTag(.unwrap_optional).?),801 .unwrap_optional => return self.genUnwrapOptional(inst.castTag(.unwrap_optional).?),
800 .wrap_optional => return self.genWrapOptional(inst.castTag(.wrap_optional).?),802 .wrap_optional => return self.genWrapOptional(inst.castTag(.wrap_optional).?),
801 .varptr => return self.genVarPtr(inst.castTag(.varptr).?),803 .varptr => return self.genVarPtr(inst.castTag(.varptr).?),
804 .xor => return self.genXor(inst.castTag(.xor).?),
802 }805 }
803 }806 }
804807
...@@ -1009,6 +1012,36 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -1009,6 +1012,36 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
1009 }1012 }
1010 }1013 }
10111014
1015 fn genBitAnd(self: *Self, inst: *ir.Inst.BinOp) !MCValue {
1016 // No side effects, so if it's unreferenced, do nothing.
1017 if (inst.base.isUnused())
1018 return MCValue.dead;
1019 switch (arch) {
1020 .arm, .armeb => return try self.genArmBinOp(&inst.base, inst.lhs, inst.rhs, .bitand),
1021 else => return self.fail(inst.base.src, "TODO implement bitwise and for {}", .{self.target.cpu.arch}),
1022 }
1023 }
1024
1025 fn genBitOr(self: *Self, inst: *ir.Inst.BinOp) !MCValue {
1026 // No side effects, so if it's unreferenced, do nothing.
1027 if (inst.base.isUnused())
1028 return MCValue.dead;
1029 switch (arch) {
1030 .arm, .armeb => return try self.genArmBinOp(&inst.base, inst.lhs, inst.rhs, .bitor),
1031 else => return self.fail(inst.base.src, "TODO implement bitwise or for {}", .{self.target.cpu.arch}),
1032 }
1033 }
1034
1035 fn genXor(self: *Self, inst: *ir.Inst.BinOp) !MCValue {
1036 // No side effects, so if it's unreferenced, do nothing.
1037 if (inst.base.isUnused())
1038 return MCValue.dead;
1039 switch (arch) {
1040 .arm, .armeb => return try self.genArmBinOp(&inst.base, inst.lhs, inst.rhs, .xor),
1041 else => return self.fail(inst.base.src, "TODO implement xor for {}", .{self.target.cpu.arch}),
1042 }
1043 }
1044
1012 fn genUnwrapOptional(self: *Self, inst: *ir.Inst.UnOp) !MCValue {1045 fn genUnwrapOptional(self: *Self, inst: *ir.Inst.UnOp) !MCValue {
1013 // No side effects, so if it's unreferenced, do nothing.1046 // No side effects, so if it's unreferenced, do nothing.
1014 if (inst.base.isUnused())1047 if (inst.base.isUnused())
...@@ -1251,13 +1284,13 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -1251,13 +1284,13 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
1251 writeInt(u32, try self.code.addManyAsArray(4), Instruction.rsb(.al, dst_reg, dst_reg, operand).toU32());1284 writeInt(u32, try self.code.addManyAsArray(4), Instruction.rsb(.al, dst_reg, dst_reg, operand).toU32());
1252 }1285 }
1253 },1286 },
1254 .booland => {1287 .booland, .bitand => {
1255 writeInt(u32, try self.code.addManyAsArray(4), Instruction.@"and"(.al, dst_reg, dst_reg, operand).toU32());1288 writeInt(u32, try self.code.addManyAsArray(4), Instruction.@"and"(.al, dst_reg, dst_reg, operand).toU32());
1256 },1289 },
1257 .boolor => {1290 .boolor, .bitor => {
1258 writeInt(u32, try self.code.addManyAsArray(4), Instruction.orr(.al, dst_reg, dst_reg, operand).toU32());1291 writeInt(u32, try self.code.addManyAsArray(4), Instruction.orr(.al, dst_reg, dst_reg, operand).toU32());
1259 },1292 },
1260 .not => {1293 .not, .xor => {
1261 writeInt(u32, try self.code.addManyAsArray(4), Instruction.eor(.al, dst_reg, dst_reg, operand).toU32());1294 writeInt(u32, try self.code.addManyAsArray(4), Instruction.eor(.al, dst_reg, dst_reg, operand).toU32());
1262 },1295 },
1263 else => unreachable, // not a binary instruction1296 else => unreachable, // not a binary instruction
src/ir.zig+6
...@@ -56,7 +56,9 @@ pub const Inst = struct {...@@ -56,7 +56,9 @@ pub const Inst = struct {
56 alloc,56 alloc,
57 arg,57 arg,
58 assembly,58 assembly,
59 bitand,
59 bitcast,60 bitcast,
61 bitor,
60 block,62 block,
61 br,63 br,
62 breakpoint,64 breakpoint,
...@@ -93,6 +95,7 @@ pub const Inst = struct {...@@ -93,6 +95,7 @@ pub const Inst = struct {
93 intcast,95 intcast,
94 unwrap_optional,96 unwrap_optional,
95 wrap_optional,97 wrap_optional,
98 xor,
96 switchbr,99 switchbr,
97100
98 pub fn Type(tag: Tag) type {101 pub fn Type(tag: Tag) type {
...@@ -130,6 +133,9 @@ pub const Inst = struct {...@@ -130,6 +133,9 @@ pub const Inst = struct {
130 .store,133 .store,
131 .booland,134 .booland,
132 .boolor,135 .boolor,
136 .bitand,
137 .bitor,
138 .xor,
133 => BinOp,139 => BinOp,
134140
135 .arg => Arg,141 .arg => Arg,
src/zir.zig+3
...@@ -2342,6 +2342,9 @@ const EmitZIR = struct {...@@ -2342,6 +2342,9 @@ const EmitZIR = struct {
2342 .cmp_neq => try self.emitBinOp(inst.src, new_body, inst.castTag(.cmp_neq).?, .cmp_neq),2342 .cmp_neq => try self.emitBinOp(inst.src, new_body, inst.castTag(.cmp_neq).?, .cmp_neq),
2343 .booland => try self.emitBinOp(inst.src, new_body, inst.castTag(.booland).?, .booland),2343 .booland => try self.emitBinOp(inst.src, new_body, inst.castTag(.booland).?, .booland),
2344 .boolor => try self.emitBinOp(inst.src, new_body, inst.castTag(.boolor).?, .boolor),2344 .boolor => try self.emitBinOp(inst.src, new_body, inst.castTag(.boolor).?, .boolor),
2345 .bitand => try self.emitBinOp(inst.src, new_body, inst.castTag(.bitand).?, .bitand),
2346 .bitor => try self.emitBinOp(inst.src, new_body, inst.castTag(.bitor).?, .bitor),
2347 .xor => try self.emitBinOp(inst.src, new_body, inst.castTag(.xor).?, .xor),
23452348
2346 .bitcast => try self.emitCast(inst.src, new_body, inst.castTag(.bitcast).?, .bitcast),2349 .bitcast => try self.emitCast(inst.src, new_body, inst.castTag(.bitcast).?, .bitcast),
2347 .intcast => try self.emitCast(inst.src, new_body, inst.castTag(.intcast).?, .intcast),2350 .intcast => try self.emitCast(inst.src, new_body, inst.castTag(.intcast).?, .intcast),
src/zir_sema.zig+61-2
...@@ -1459,7 +1459,66 @@ fn analyzeInstShr(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError...@@ -1459,7 +1459,66 @@ fn analyzeInstShr(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError
1459}1459}
14601460
1461fn analyzeInstBitwise(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst {1461fn analyzeInstBitwise(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst {
1462 return mod.fail(scope, inst.base.src, "TODO implement analyzeInstBitwise", .{});1462 const tracy = trace(@src());
1463 defer tracy.end();
1464
1465 const lhs = try resolveInst(mod, scope, inst.positionals.lhs);
1466 const rhs = try resolveInst(mod, scope, inst.positionals.rhs);
1467
1468 const instructions = &[_]*Inst{ lhs, rhs };
1469 const resolved_type = try mod.resolvePeerTypes(scope, instructions);
1470 const casted_lhs = try mod.coerce(scope, resolved_type, lhs);
1471 const casted_rhs = try mod.coerce(scope, resolved_type, rhs);
1472
1473 const scalar_type = if (resolved_type.zigTypeTag() == .Vector)
1474 resolved_type.elemType()
1475 else
1476 resolved_type;
1477
1478 const scalar_tag = scalar_type.zigTypeTag();
1479
1480 if (lhs.ty.zigTypeTag() == .Vector and rhs.ty.zigTypeTag() == .Vector) {
1481 if (lhs.ty.arrayLen() != rhs.ty.arrayLen()) {
1482 return mod.fail(scope, inst.base.src, "vector length mismatch: {} and {}", .{
1483 lhs.ty.arrayLen(),
1484 rhs.ty.arrayLen(),
1485 });
1486 }
1487 return mod.fail(scope, inst.base.src, "TODO implement support for vectors in analyzeInstBitwise", .{});
1488 } else if (lhs.ty.zigTypeTag() == .Vector or rhs.ty.zigTypeTag() == .Vector) {
1489 return mod.fail(scope, inst.base.src, "mixed scalar and vector operands to binary expression: '{}' and '{}'", .{
1490 lhs.ty,
1491 rhs.ty,
1492 });
1493 }
1494
1495 const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt;
1496
1497 if (!is_int) {
1498 return mod.fail(scope, inst.base.src, "invalid operands to binary bitwise expression: '{}' and '{}'", .{ @tagName(lhs.ty.zigTypeTag()), @tagName(rhs.ty.zigTypeTag()) });
1499 }
1500
1501 if (casted_lhs.value()) |lhs_val| {
1502 if (casted_rhs.value()) |rhs_val| {
1503 if (lhs_val.isUndef() or rhs_val.isUndef()) {
1504 return mod.constInst(scope, inst.base.src, .{
1505 .ty = resolved_type,
1506 .val = Value.initTag(.undef),
1507 });
1508 }
1509 return mod.fail(scope, inst.base.src, "TODO implement comptime bitwise operations", .{});
1510 }
1511 }
1512
1513 const b = try mod.requireRuntimeBlock(scope, inst.base.src);
1514 const ir_tag = switch (inst.base.tag) {
1515 .bitand => Inst.Tag.bitand,
1516 .bitor => Inst.Tag.bitor,
1517 .xor => Inst.Tag.xor,
1518 else => unreachable,
1519 };
1520
1521 return mod.addBinOp(b, inst.base.src, scalar_type, ir_tag, casted_lhs, casted_rhs);
1463}1522}
14641523
1465fn analyzeInstBitNot(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {1524fn analyzeInstBitNot(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {
...@@ -1502,7 +1561,7 @@ fn analyzeInstArithmetic(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) Inn...@@ -1502,7 +1561,7 @@ fn analyzeInstArithmetic(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) Inn
1502 }1561 }
1503 return mod.fail(scope, inst.base.src, "TODO implement support for vectors in analyzeInstBinOp", .{});1562 return mod.fail(scope, inst.base.src, "TODO implement support for vectors in analyzeInstBinOp", .{});
1504 } else if (lhs.ty.zigTypeTag() == .Vector or rhs.ty.zigTypeTag() == .Vector) {1563 } else if (lhs.ty.zigTypeTag() == .Vector or rhs.ty.zigTypeTag() == .Vector) {
1505 return mod.fail(scope, inst.base.src, "mixed scalar and vector operands to comparison operator: '{}' and '{}'", .{1564 return mod.fail(scope, inst.base.src, "mixed scalar and vector operands to binary expression: '{}' and '{}'", .{
1506 lhs.ty,1565 lhs.ty,
1507 rhs.ty,1566 rhs.ty,
1508 });1567 });
test/stage2/arm.zig+134-1
...@@ -115,7 +115,8 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -115,7 +115,8 @@ pub fn addCases(ctx: *TestContext) !void {
115 }115 }
116116
117 {117 {
118 var case = ctx.exe("addition", linux_arm);118 var case = ctx.exe("arithmetic operations", linux_arm);
119
119 // Add two numbers120 // Add two numbers
120 case.addCompareOutput(121 case.addCompareOutput(
121 \\export fn _start() noreturn {122 \\export fn _start() noreturn {
...@@ -148,5 +149,137 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -148,5 +149,137 @@ pub fn addCases(ctx: *TestContext) !void {
148 ,149 ,
149 "12345612345678",150 "12345612345678",
150 );151 );
152
153 // Subtract two numbers
154 case.addCompareOutput(
155 \\export fn _start() noreturn {
156 \\ print(10, 5);
157 \\ print(4, 3);
158 \\ exit();
159 \\}
160 \\
161 \\fn print(a: u32, b: u32) void {
162 \\ asm volatile ("svc #0"
163 \\ :
164 \\ : [number] "{r7}" (4),
165 \\ [arg3] "{r2}" (a - b),
166 \\ [arg1] "{r0}" (1),
167 \\ [arg2] "{r1}" (@ptrToInt("123456789"))
168 \\ : "memory"
169 \\ );
170 \\ return;
171 \\}
172 \\
173 \\fn exit() noreturn {
174 \\ asm volatile ("svc #0"
175 \\ :
176 \\ : [number] "{r7}" (1),
177 \\ [arg1] "{r0}" (0)
178 \\ : "memory"
179 \\ );
180 \\ unreachable;
181 \\}
182 ,
183 "123451",
184 );
185
186 // Bitwise And
187 case.addCompareOutput(
188 \\export fn _start() noreturn {
189 \\ print(8, 9);
190 \\ print(3, 7);
191 \\ exit();
192 \\}
193 \\
194 \\fn print(a: u32, b: u32) void {
195 \\ asm volatile ("svc #0"
196 \\ :
197 \\ : [number] "{r7}" (4),
198 \\ [arg3] "{r2}" (a & b),
199 \\ [arg1] "{r0}" (1),
200 \\ [arg2] "{r1}" (@ptrToInt("123456789"))
201 \\ : "memory"
202 \\ );
203 \\ return;
204 \\}
205 \\
206 \\fn exit() noreturn {
207 \\ asm volatile ("svc #0"
208 \\ :
209 \\ : [number] "{r7}" (1),
210 \\ [arg1] "{r0}" (0)
211 \\ : "memory"
212 \\ );
213 \\ unreachable;
214 \\}
215 ,
216 "12345678123",
217 );
218
219 // Bitwise Or
220 case.addCompareOutput(
221 \\export fn _start() noreturn {
222 \\ print(4, 2);
223 \\ print(3, 7);
224 \\ exit();
225 \\}
226 \\
227 \\fn print(a: u32, b: u32) void {
228 \\ asm volatile ("svc #0"
229 \\ :
230 \\ : [number] "{r7}" (4),
231 \\ [arg3] "{r2}" (a | b),
232 \\ [arg1] "{r0}" (1),
233 \\ [arg2] "{r1}" (@ptrToInt("123456789"))
234 \\ : "memory"
235 \\ );
236 \\ return;
237 \\}
238 \\
239 \\fn exit() noreturn {
240 \\ asm volatile ("svc #0"
241 \\ :
242 \\ : [number] "{r7}" (1),
243 \\ [arg1] "{r0}" (0)
244 \\ : "memory"
245 \\ );
246 \\ unreachable;
247 \\}
248 ,
249 "1234561234567",
250 );
251
252 // Bitwise Xor
253 case.addCompareOutput(
254 \\export fn _start() noreturn {
255 \\ print(42, 42);
256 \\ print(3, 5);
257 \\ exit();
258 \\}
259 \\
260 \\fn print(a: u32, b: u32) void {
261 \\ asm volatile ("svc #0"
262 \\ :
263 \\ : [number] "{r7}" (4),
264 \\ [arg3] "{r2}" (a ^ b),
265 \\ [arg1] "{r0}" (1),
266 \\ [arg2] "{r1}" (@ptrToInt("123456789"))
267 \\ : "memory"
268 \\ );
269 \\ return;
270 \\}
271 \\
272 \\fn exit() noreturn {
273 \\ asm volatile ("svc #0"
274 \\ :
275 \\ : [number] "{r7}" (1),
276 \\ [arg1] "{r0}" (0)
277 \\ : "memory"
278 \\ );
279 \\ unreachable;
280 \\}
281 ,
282 "123456",
283 );
151 }284 }
152}285}