Commit 021f537863

kcbanner <kcbanner@gmail.com>
2023-07-08 06:20:37
dwarf: fixup default endianness in ExpressionOptions, add control flow tests
1 parent 54ca62f
Changed files (1)
lib
std
lib/std/dwarf/expressions.zig
@@ -33,7 +33,7 @@ pub const ExpressionOptions = struct {
     addr_size: u8 = @sizeOf(usize),
 
     /// Endianess of the target architecture
-    endian: std.builtin.Endian = .Little,
+    endian: std.builtin.Endian = builtin.target.cpu.arch.endian(),
 
     /// Restrict the stack machine to a subset of opcodes used in call frame instructions
     call_frame_context: bool = false,
@@ -272,7 +272,7 @@ pub fn StackMachine(comptime options: ExpressionOptions) type {
             return self.stack.items[self.stack.items.len - 1];
         }
 
-        /// Reads an opcode and its operands from the stream and executes it
+        /// Reads an opcode and its operands from `stream`, then executes it
         pub fn step(
             self: *Self,
             stream: *std.io.FixedBufferStream([]const u8),
@@ -607,7 +607,7 @@ pub fn StackMachine(comptime options: ExpressionOptions) type {
                         const a_int: isize = @bitCast(a.asIntegral() catch unreachable);
                         const b_int: isize = @bitCast(b.asIntegral() catch unreachable);
                         const result = @intFromBool(switch (opcode) {
-                            OP.le => b_int < a_int,
+                            OP.le => b_int <= a_int,
                             OP.ge => b_int >= a_int,
                             OP.eq => b_int == a_int,
                             OP.lt => b_int < a_int,
@@ -635,7 +635,7 @@ pub fn StackMachine(comptime options: ExpressionOptions) type {
                             try std.math.add(isize, @as(isize, @intCast(stream.pos)), branch_offset),
                         ) orelse return error.InvalidExpression;
 
-                        if (new_pos < 0 or new_pos >= stream.buffer.len) return error.InvalidExpression;
+                        if (new_pos < 0 or new_pos > stream.buffer.len) return error.InvalidExpression;
                         stream.pos = new_pos;
                     }
                 },
@@ -657,12 +657,16 @@ pub fn StackMachine(comptime options: ExpressionOptions) type {
                 OP.convert => {
                     if (self.stack.items.len == 0) return error.InvalidExpression;
                     const type_offset = (try readOperand(stream, opcode)).?.generic;
-                    _ = type_offset;
 
-                    // TODO: Load the DW_TAG_base_type entry in context.compile_unit, find a conversion operator
-                    //       from the old type to the new type, run it.
-
-                    return error.UnimplementedTypeConversion;
+                    // TODO: Load the DW_TAG_base_type entries in context.compile_unit and verify both types are the same size
+                    const value = self.stack.items[self.stack.items.len - 1];
+                    if (type_offset == 0) {
+                        self.stack.items[self.stack.items.len - 1] = .{ .generic = try value.asIntegral() };
+                    } else {
+                        // TODO: Load the DW_TAG_base_type entry in context.compile_unit, find a conversion operator
+                        //       from the old type to the new type, run it.
+                        return error.UnimplementedTypeConversion;
+                    }
                 },
                 OP.reinterpret => {
                     if (self.stack.items.len == 0) return error.InvalidExpression;
@@ -1373,4 +1377,66 @@ test "DWARF expressions" {
         _ = try stack_machine.run(program.items, allocator, context, null);
         try testing.expectEqual(@as(usize, 0x0ff0), stack_machine.stack.popOrNull().?.generic);
     }
+
+
+    // Control Flow Operations
+    {
+        var context = ExpressionContext{};
+        const expected = .{
+            .{ OP.le, 1, 1, 0 },
+            .{ OP.ge, 1, 0, 1 },
+            .{ OP.eq, 1, 0, 0 },
+            .{ OP.lt, 0, 1, 0 },
+            .{ OP.gt, 0, 0, 1 },
+            .{ OP.ne, 0, 1, 1 },
+        };
+
+        inline for (expected) |e| {
+            stack_machine.reset();
+            program.clearRetainingCapacity();
+
+            try b.writeConst(writer, u16, 0);
+            try b.writeConst(writer, u16, 0);
+            try b.writeOpcode(writer, e[0]);
+            try b.writeConst(writer, u16, 0);
+            try b.writeConst(writer, u16, 1);
+            try b.writeOpcode(writer, e[0]);
+            try b.writeConst(writer, u16, 1);
+            try b.writeConst(writer, u16, 0);
+            try b.writeOpcode(writer, e[0]);
+            _ = try stack_machine.run(program.items, allocator, context, null);
+            try testing.expectEqual(@as(usize, e[3]), stack_machine.stack.popOrNull().?.generic);
+            try testing.expectEqual(@as(usize, e[2]), stack_machine.stack.popOrNull().?.generic);
+            try testing.expectEqual(@as(usize, e[1]), stack_machine.stack.popOrNull().?.generic);
+        }
+
+        stack_machine.reset();
+        program.clearRetainingCapacity();
+        try b.writeLiteral(writer, 2);
+        try b.writeSkip(writer, 1);
+        try b.writeLiteral(writer, 3);
+        _ = try stack_machine.run(program.items, allocator, context, null);
+        try testing.expectEqual(@as(usize, 2), stack_machine.stack.popOrNull().?.generic);
+
+
+        stack_machine.reset();
+        program.clearRetainingCapacity();
+        try b.writeLiteral(writer, 2);
+        try b.writeBra(writer, 1);
+        try b.writeLiteral(writer, 3);
+        try b.writeLiteral(writer, 0);
+        try b.writeBra(writer, 1);
+        try b.writeLiteral(writer, 4);
+        try b.writeLiteral(writer, 5);
+        _ = try stack_machine.run(program.items, allocator, context, null);
+        try testing.expectEqual(@as(usize, 5), stack_machine.stack.popOrNull().?.generic);
+        try testing.expectEqual(@as(usize, 4), stack_machine.stack.popOrNull().?.generic);
+        try testing.expect(stack_machine.stack.popOrNull() == null);
+
+        // TODO: Test call2, call4, call_ref once implemented
+
+    }
+
+
 }
+