implement signed multiplication

This commit is contained in:
David Gonzalez Martin 2023-11-12 20:06:12 -06:00
parent be6ea6c45d
commit d390ee08f6
5 changed files with 112 additions and 44 deletions

View File

@ -552,6 +552,7 @@ pub const BinaryOperation = struct {
logical_and, logical_and,
logical_xor, logical_xor,
logical_or, logical_or,
multiply,
}; };
}; };

View File

@ -238,6 +238,7 @@ pub const BinaryOperation = struct {
logical_and, logical_and,
logical_xor, logical_xor,
logical_or, logical_or,
multiply,
}; };
pub const List = BlockList(@This()); pub const List = BlockList(@This());
@ -737,6 +738,7 @@ pub const Builder = struct {
.logical_and => .logical_and, .logical_and => .logical_and,
.logical_xor => .logical_xor, .logical_xor => .logical_xor,
.logical_or => .logical_or, .logical_or => .logical_or,
.multiply => .multiply,
}, },
.type = try builder.translateType(sema_binary_operation.type), .type = try builder.translateType(sema_binary_operation.type),
}); });

View File

@ -40,15 +40,15 @@ pub const Logger = enum {
pub var bitset = std.EnumSet(Logger).initMany(&.{ pub var bitset = std.EnumSet(Logger).initMany(&.{
.instruction_selection_ir_function, .instruction_selection_ir_function,
.instruction_selection_mir_function, .instruction_selection_mir_function,
.instruction_selection_register_operand_list, // .instruction_selection_register_operand_list,
.register_allocation_block, // .register_allocation_block,
.register_allocation_problematic_hint, // .register_allocation_problematic_hint,
.register_allocation_assignment, // .register_allocation_assignment,
.register_allocation_reload, // .register_allocation_reload,
.register_allocation_function_before, // .register_allocation_function_before,
.register_allocation_new_instruction, // .register_allocation_new_instruction,
.register_allocation_new_instruction_function_before, // .register_allocation_new_instruction_function_before,
.register_allocation_instruction_avoid_copy, // .register_allocation_instruction_avoid_copy,
.register_allocation_function_after, .register_allocation_function_after,
// .register_allocation_operand_list_verification, // .register_allocation_operand_list_verification,
// .encoding, // .encoding,
@ -1491,6 +1491,8 @@ const Instruction = struct {
and32rr, and32rr,
call64pcrel32, call64pcrel32,
copy, copy,
imul32rm,
imul32rr,
lea64r, lea64r,
mov32r0, mov32r0,
mov32rm, 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 = .{ .lea64r = .{
// .format = .mrm_source_mem, // .format = .mrm_source_mem,
.opcode = 0x8d, .opcode = 0x8d,
@ -2951,6 +2987,10 @@ pub const MIR = struct {
.i32 => .or32rr, .i32 => .or32rr,
else => unreachable, else => unreachable,
}, },
.multiply => switch (value_type) {
.i32 => .imul32rr,
else => unreachable,
},
}; };
const instruction_descriptor = instruction_descriptors.get(instruction_id); const instruction_descriptor = instruction_descriptors.get(instruction_id);
@ -3018,6 +3058,10 @@ pub const MIR = struct {
.i32 => .or32rm, .i32 => .or32rm,
else => unreachable, else => unreachable,
}, },
.multiply => switch (value_type) {
.i32 => .imul32rm,
else => unreachable,
},
}; };
try instruction_selection.folded_loads.putNoClobber(mir.allocator, ir_binary_operation.right, {}); 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)), else => |t| @panic(@tagName(t)),
} }
}, },
.add32rr, .sub32rr => { .add32rr,
.sub32rr,
.imul32rr,
=> {
assert(instruction.operands.items.len == 3); assert(instruction.operands.items.len == 3);
const instruction_descriptor = instruction_descriptors.get(instruction.id); const instruction_descriptor = instruction_descriptors.get(instruction.id);
const opcode: u8 = @intCast(instruction_descriptor.opcode); const opcode: u8 = @intCast(instruction_descriptor.opcode);
@ -4631,7 +4678,46 @@ pub const MIR = struct {
}; };
try image.section_manager.appendCodeByte(@bitCast(modrm)); 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); assert(instruction.operands.items.len == 3);
const instruction_descriptor = instruction_descriptors.get(instruction.id); const instruction_descriptor = instruction_descriptors.get(instruction.id);
const opcode: u8 = @intCast(instruction_descriptor.opcode); 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)), else => |t| @panic(@tagName(t)),
} }

View File

@ -543,6 +543,7 @@ const Analyzer = struct {
.logical_and => .logical_and, .logical_and => .logical_and,
.logical_xor => .logical_xor, .logical_xor => .logical_xor,
.logical_or => .logical_or, .logical_or => .logical_or,
.multiply => .multiply,
else => |t| @panic(@tagName(t)), else => |t| @panic(@tagName(t)),
}, },
}); });
@ -1013,6 +1014,7 @@ const Analyzer = struct {
.logical_and, .logical_and,
.logical_xor, .logical_xor,
.logical_or, .logical_or,
.multiply,
=> try analyzer.processBinaryOperation(scope_index, expect_type, node_index), => try analyzer.processBinaryOperation(scope_index, expect_type, node_index),
.expression_group => return try analyzer.resolveNode(value, scope_index, expect_type, node.left), //unreachable, .expression_group => return try analyzer.resolveNode(value, scope_index, expect_type, node.left), //unreachable,
else => |t| @panic(@tagName(t)), else => |t| @panic(@tagName(t)),

View File

@ -158,6 +158,7 @@ pub const Node = packed struct(u128) {
logical_xor = 64, logical_xor = 64,
expression_group = 65, expression_group = 65,
logical_or = 66, logical_or = 66,
multiply = 67,
}; };
}; };
@ -717,6 +718,7 @@ const Analyzer = struct {
logical_and, logical_and,
logical_xor, logical_xor,
logical_or, logical_or,
multiply,
}; };
const operator_precedence = std.EnumArray(PrecedenceOperator, i32).init(.{ const operator_precedence = std.EnumArray(PrecedenceOperator, i32).init(.{
@ -727,6 +729,7 @@ const Analyzer = struct {
.logical_and = 40, .logical_and = 40,
.logical_xor = 40, .logical_xor = 40,
.logical_or = 40, .logical_or = 40,
.multiply = 70,
}); });
const operator_associativity = std.EnumArray(PrecedenceOperator, Associativity).init(.{ const operator_associativity = std.EnumArray(PrecedenceOperator, Associativity).init(.{
@ -737,6 +740,7 @@ const Analyzer = struct {
.logical_and = .left, .logical_and = .left,
.logical_xor = .left, .logical_xor = .left,
.logical_or = .left, .logical_or = .left,
.multiply = .left,
}); });
const operator_node_id = std.EnumArray(PrecedenceOperator, Node.Id).init(.{ const operator_node_id = std.EnumArray(PrecedenceOperator, Node.Id).init(.{
@ -747,6 +751,7 @@ const Analyzer = struct {
.logical_and = .logical_and, .logical_and = .logical_and,
.logical_xor = .logical_xor, .logical_xor = .logical_xor,
.logical_or = .logical_or, .logical_or = .logical_or,
.multiply = .multiply,
}); });
fn expressionPrecedence(analyzer: *Analyzer, minimum_precedence: i32) !Node.Index { fn expressionPrecedence(analyzer: *Analyzer, minimum_precedence: i32) !Node.Index {
@ -807,6 +812,10 @@ const Analyzer = struct {
.equal => unreachable, .equal => unreachable,
else => .logical_or, else => .logical_or,
}, },
.asterisk => switch (next_token_id) {
.equal => unreachable,
else => .multiply,
},
else => |t| @panic(@tagName(t)), else => |t| @panic(@tagName(t)),
}; };
} else { } else {
@ -833,6 +842,7 @@ const Analyzer = struct {
.logical_and, .logical_and,
.logical_xor, .logical_xor,
.logical_or, .logical_or,
.multiply,
=> false, => false,
.compare_equal, .compare_equal,
.compare_not_equal, .compare_not_equal,