From d390ee08f681da8a4695f8bb718c4b3ca3acec06 Mon Sep 17 00:00:00 2001 From: David Gonzalez Martin Date: Sun, 12 Nov 2023 20:06:12 -0600 Subject: [PATCH] implement signed multiplication --- src/Compilation.zig | 1 + src/backend/intermediate_representation.zig | 2 + src/backend/x86_64.zig | 141 ++++++++++++++------ src/frontend/semantic_analyzer.zig | 2 + src/frontend/syntactic_analyzer.zig | 10 ++ 5 files changed, 112 insertions(+), 44 deletions(-) diff --git a/src/Compilation.zig b/src/Compilation.zig index 66fd506..bb44955 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -552,6 +552,7 @@ pub const BinaryOperation = struct { logical_and, logical_xor, logical_or, + multiply, }; }; diff --git a/src/backend/intermediate_representation.zig b/src/backend/intermediate_representation.zig index 17ade03..5043bac 100644 --- a/src/backend/intermediate_representation.zig +++ b/src/backend/intermediate_representation.zig @@ -238,6 +238,7 @@ pub const BinaryOperation = struct { logical_and, logical_xor, logical_or, + multiply, }; pub const List = BlockList(@This()); @@ -737,6 +738,7 @@ pub const Builder = struct { .logical_and => .logical_and, .logical_xor => .logical_xor, .logical_or => .logical_or, + .multiply => .multiply, }, .type = try builder.translateType(sema_binary_operation.type), }); diff --git a/src/backend/x86_64.zig b/src/backend/x86_64.zig index 1ee621e..b79e8ba 100644 --- a/src/backend/x86_64.zig +++ b/src/backend/x86_64.zig @@ -40,15 +40,15 @@ pub const Logger = enum { pub var bitset = std.EnumSet(Logger).initMany(&.{ .instruction_selection_ir_function, .instruction_selection_mir_function, - .instruction_selection_register_operand_list, - .register_allocation_block, - .register_allocation_problematic_hint, - .register_allocation_assignment, - .register_allocation_reload, - .register_allocation_function_before, - .register_allocation_new_instruction, - .register_allocation_new_instruction_function_before, - .register_allocation_instruction_avoid_copy, + // .instruction_selection_register_operand_list, + // .register_allocation_block, + // .register_allocation_problematic_hint, + // .register_allocation_assignment, + // .register_allocation_reload, + // .register_allocation_function_before, + // .register_allocation_new_instruction, + // .register_allocation_new_instruction_function_before, + // .register_allocation_instruction_avoid_copy, .register_allocation_function_after, // .register_allocation_operand_list_verification, // .encoding, @@ -1491,6 +1491,8 @@ const Instruction = struct { and32rr, call64pcrel32, copy, + imul32rm, + imul32rr, lea64r, mov32r0, mov32rm, @@ -1918,6 +1920,40 @@ const instruction_descriptors = std.EnumArray(Instruction.Id, Instruction.Descri }, }, }, + .imul32rr = .{ + .opcode = 0x6b, + .operands = &.{ + .{ + .id = .gp32, + .kind = .dst, + }, + .{ + .id = .gp32, + .kind = .src, + }, + .{ + .id = .gp32, + .kind = .src, + }, + }, + }, + .imul32rm = .{ + .opcode = 0x6b, + .operands = &.{ + .{ + .id = .gp32, + .kind = .dst, + }, + .{ + .id = .gp32, + .kind = .src, + }, + .{ + .id = .i32mem, + .kind = .src, + }, + }, + }, .lea64r = .{ // .format = .mrm_source_mem, .opcode = 0x8d, @@ -2951,6 +2987,10 @@ pub const MIR = struct { .i32 => .or32rr, else => unreachable, }, + .multiply => switch (value_type) { + .i32 => .imul32rr, + else => unreachable, + }, }; const instruction_descriptor = instruction_descriptors.get(instruction_id); @@ -3018,6 +3058,10 @@ pub const MIR = struct { .i32 => .or32rm, else => unreachable, }, + .multiply => switch (value_type) { + .i32 => .imul32rm, + else => unreachable, + }, }; try instruction_selection.folded_loads.putNoClobber(mir.allocator, ir_binary_operation.right, {}); @@ -4604,7 +4648,10 @@ pub const MIR = struct { else => |t| @panic(@tagName(t)), } }, - .add32rr, .sub32rr => { + .add32rr, + .sub32rr, + .imul32rr, + => { assert(instruction.operands.items.len == 3); const instruction_descriptor = instruction_descriptors.get(instruction.id); const opcode: u8 = @intCast(instruction_descriptor.opcode); @@ -4631,7 +4678,46 @@ pub const MIR = struct { }; try image.section_manager.appendCodeByte(@bitCast(modrm)); }, - .add32rm, .sub32rm, .and32rm, .xor32rm, .or32rm => { + .mov32mi => { + assert(instruction.operands.items.len == 2); + + const instruction_descriptor = instruction_descriptors.get(instruction.id); + const opcode: u8 = @intCast(instruction_descriptor.opcode); + try image.section_manager.appendCodeByte(opcode); + + const destination_operand_index = instruction.operands.items[0]; + const destination_operand = mir.operands.get(destination_operand_index); + switch (destination_operand.u.memory.addressing_mode.base) { + .register_base => unreachable, + .frame_index => |frame_index| { + const modrm = ModRm{ + .rm = @intFromEnum(Encoding.GP64.bp), + .reg = 0, + .mod = @as(u2, @intFromBool(false)) << 1 | @intFromBool(true), + }; + try image.section_manager.appendCodeByte(@bitCast(modrm)); + + const stack_offset = computeStackOffset(function.instruction_selection.stack_objects.items[0 .. frame_index + 1]); + const displacement_bytes: u3 = if (std.math.cast(i8, stack_offset)) |_| @sizeOf(i8) else if (std.math.cast(i32, stack_offset)) |_| @sizeOf(i32) else unreachable; + + const stack_bytes = std.mem.asBytes(&stack_offset)[0..displacement_bytes]; + try image.section_manager.appendCode(stack_bytes); + }, + } + + const source_operand_index = instruction.operands.items[1]; + const source_operand = mir.operands.get(source_operand_index); + const source_immediate: u32 = @intCast(source_operand.u.immediate); + + try image.section_manager.appendCode(std.mem.asBytes(&source_immediate)); + }, + .add32rm, + .sub32rm, + .and32rm, + .xor32rm, + .or32rm, + .imul32rm, + => { assert(instruction.operands.items.len == 3); const instruction_descriptor = instruction_descriptors.get(instruction.id); const opcode: u8 = @intCast(instruction_descriptor.opcode); @@ -4670,39 +4756,6 @@ pub const MIR = struct { }, } }, - .mov32mi => { - assert(instruction.operands.items.len == 2); - - const instruction_descriptor = instruction_descriptors.get(instruction.id); - const opcode: u8 = @intCast(instruction_descriptor.opcode); - try image.section_manager.appendCodeByte(opcode); - - const destination_operand_index = instruction.operands.items[0]; - const destination_operand = mir.operands.get(destination_operand_index); - switch (destination_operand.u.memory.addressing_mode.base) { - .register_base => unreachable, - .frame_index => |frame_index| { - const modrm = ModRm{ - .rm = @intFromEnum(Encoding.GP64.bp), - .reg = 0, - .mod = @as(u2, @intFromBool(false)) << 1 | @intFromBool(true), - }; - try image.section_manager.appendCodeByte(@bitCast(modrm)); - - const stack_offset = computeStackOffset(function.instruction_selection.stack_objects.items[0 .. frame_index + 1]); - const displacement_bytes: u3 = if (std.math.cast(i8, stack_offset)) |_| @sizeOf(i8) else if (std.math.cast(i32, stack_offset)) |_| @sizeOf(i32) else unreachable; - - const stack_bytes = std.mem.asBytes(&stack_offset)[0..displacement_bytes]; - try image.section_manager.appendCode(stack_bytes); - }, - } - - const source_operand_index = instruction.operands.items[1]; - const source_operand = mir.operands.get(source_operand_index); - const source_immediate: u32 = @intCast(source_operand.u.immediate); - - try image.section_manager.appendCode(std.mem.asBytes(&source_immediate)); - }, else => |t| @panic(@tagName(t)), } diff --git a/src/frontend/semantic_analyzer.zig b/src/frontend/semantic_analyzer.zig index 2c671bd..31124e5 100644 --- a/src/frontend/semantic_analyzer.zig +++ b/src/frontend/semantic_analyzer.zig @@ -543,6 +543,7 @@ const Analyzer = struct { .logical_and => .logical_and, .logical_xor => .logical_xor, .logical_or => .logical_or, + .multiply => .multiply, else => |t| @panic(@tagName(t)), }, }); @@ -1013,6 +1014,7 @@ const Analyzer = struct { .logical_and, .logical_xor, .logical_or, + .multiply, => try analyzer.processBinaryOperation(scope_index, expect_type, node_index), .expression_group => return try analyzer.resolveNode(value, scope_index, expect_type, node.left), //unreachable, else => |t| @panic(@tagName(t)), diff --git a/src/frontend/syntactic_analyzer.zig b/src/frontend/syntactic_analyzer.zig index f484991..687b33f 100644 --- a/src/frontend/syntactic_analyzer.zig +++ b/src/frontend/syntactic_analyzer.zig @@ -158,6 +158,7 @@ pub const Node = packed struct(u128) { logical_xor = 64, expression_group = 65, logical_or = 66, + multiply = 67, }; }; @@ -717,6 +718,7 @@ const Analyzer = struct { logical_and, logical_xor, logical_or, + multiply, }; const operator_precedence = std.EnumArray(PrecedenceOperator, i32).init(.{ @@ -727,6 +729,7 @@ const Analyzer = struct { .logical_and = 40, .logical_xor = 40, .logical_or = 40, + .multiply = 70, }); const operator_associativity = std.EnumArray(PrecedenceOperator, Associativity).init(.{ @@ -737,6 +740,7 @@ const Analyzer = struct { .logical_and = .left, .logical_xor = .left, .logical_or = .left, + .multiply = .left, }); const operator_node_id = std.EnumArray(PrecedenceOperator, Node.Id).init(.{ @@ -747,6 +751,7 @@ const Analyzer = struct { .logical_and = .logical_and, .logical_xor = .logical_xor, .logical_or = .logical_or, + .multiply = .multiply, }); fn expressionPrecedence(analyzer: *Analyzer, minimum_precedence: i32) !Node.Index { @@ -807,6 +812,10 @@ const Analyzer = struct { .equal => unreachable, else => .logical_or, }, + .asterisk => switch (next_token_id) { + .equal => unreachable, + else => .multiply, + }, else => |t| @panic(@tagName(t)), }; } else { @@ -833,6 +842,7 @@ const Analyzer = struct { .logical_and, .logical_xor, .logical_or, + .multiply, => false, .compare_equal, .compare_not_equal,