Merge pull request #16 from birth-software/imul
implement signed multiplication
This commit is contained in:
commit
752fe9e115
@ -552,6 +552,7 @@ pub const BinaryOperation = struct {
|
|||||||
logical_and,
|
logical_and,
|
||||||
logical_xor,
|
logical_xor,
|
||||||
logical_or,
|
logical_or,
|
||||||
|
multiply,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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),
|
||||||
});
|
});
|
||||||
|
@ -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)),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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)),
|
||||||
|
@ -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,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user