| ... | @@ -1029,17 +1029,37 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1029,17 +1029,37 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void { |
| 1029 | if (self.liveness.isUnused(inst)) | 1029 | if (self.liveness.isUnused(inst)) |
| 1030 | return self.finishAir(inst, .dead, .{ ty_op.operand, .none, .none }); | 1030 | return self.finishAir(inst, .dead, .{ ty_op.operand, .none, .none }); |
| 1031 | | 1031 | |
| 1032 | const operand_ty = self.air.typeOf(ty_op.operand); | 1032 | const operand = ty_op.operand; |
| 1033 | const operand = try self.resolveInst(ty_op.operand); | 1033 | const operand_mcv = try self.resolveInst(operand); |
| 1034 | const info_a = operand_ty.intInfo(self.target.*); | 1034 | const operand_ty = self.air.typeOf(operand); |
| 1035 | const info_b = self.air.typeOfIndex(inst).intInfo(self.target.*); | 1035 | const operand_info = operand_ty.intInfo(self.target.*); |
| 1036 | if (info_a.signedness != info_b.signedness) | 1036 | |
| 1037 | return self.fail("TODO gen intcast sign safety in semantic analysis", .{}); | 1037 | const dest_ty = self.air.typeOfIndex(inst); |
| | 1038 | const dest_info = dest_ty.intInfo(self.target.*); |
| 1038 | | 1039 | |
| 1039 | if (info_a.bits == info_b.bits) | 1040 | const result: MCValue = result: { |
| 1040 | return self.finishAir(inst, operand, .{ ty_op.operand, .none, .none }); | 1041 | const operand_lock: ?RegisterLock = switch (operand_mcv) { |
| | 1042 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| | 1043 | else => null, |
| | 1044 | }; |
| | 1045 | defer if (operand_lock) |lock| self.register_manager.unlockReg(lock); |
| | 1046 | |
| | 1047 | if (dest_info.bits > operand_info.bits) { |
| | 1048 | const dest_mcv = try self.allocRegOrMem(inst, true); |
| | 1049 | try self.setRegOrMem(self.air.typeOfIndex(inst), dest_mcv, operand_mcv); |
| | 1050 | break :result dest_mcv; |
| | 1051 | } else { |
| | 1052 | if (self.reuseOperand(inst, operand, 0, operand_mcv)) { |
| | 1053 | break :result operand_mcv; |
| | 1054 | } else { |
| | 1055 | const dest_mcv = try self.allocRegOrMem(inst, true); |
| | 1056 | try self.setRegOrMem(self.air.typeOfIndex(inst), dest_mcv, operand_mcv); |
| | 1057 | break :result dest_mcv; |
| | 1058 | } |
| | 1059 | } |
| | 1060 | }; |
| 1041 | | 1061 | |
| 1042 | return self.fail("TODO implement intCast for {}", .{self.target.cpu.arch}); | 1062 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 1043 | } | 1063 | } |
| 1044 | | 1064 | |
| 1045 | fn truncRegister( | 1065 | fn truncRegister( |
| ... | @@ -1065,6 +1085,8 @@ fn truncRegister( | ... | @@ -1065,6 +1085,8 @@ fn truncRegister( |
| 1065 | }); | 1085 | }); |
| 1066 | }, | 1086 | }, |
| 1067 | 32, 64 => { | 1087 | 32, 64 => { |
| | 1088 | assert(dest_reg.size() == operand_reg.size()); |
| | 1089 | |
| 1068 | _ = try self.addInst(.{ | 1090 | _ = try self.addInst(.{ |
| 1069 | .tag = .mov_register, | 1091 | .tag = .mov_register, |
| 1070 | .data = .{ .rr = .{ | 1092 | .data = .{ .rr = .{ |
| ... | @@ -2955,6 +2977,8 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type | ... | @@ -2955,6 +2977,8 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type |
| 2955 | defer if (addr_reg_lock) |reg| self.register_manager.unlockReg(reg); | 2977 | defer if (addr_reg_lock) |reg| self.register_manager.unlockReg(reg); |
| 2956 | | 2978 | |
| 2957 | switch (value) { | 2979 | switch (value) { |
| | 2980 | .dead => unreachable, |
| | 2981 | .undef => unreachable, |
| 2958 | .register => |value_reg| { | 2982 | .register => |value_reg| { |
| 2959 | try self.genStrRegister(value_reg, addr_reg, value_ty); | 2983 | try self.genStrRegister(value_reg, addr_reg, value_ty); |
| 2960 | }, | 2984 | }, |
| ... | @@ -2968,7 +2992,41 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type | ... | @@ -2968,7 +2992,41 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type |
| 2968 | try self.genSetReg(value_ty, tmp_reg, value); | 2992 | try self.genSetReg(value_ty, tmp_reg, value); |
| 2969 | try self.store(ptr, .{ .register = tmp_reg }, ptr_ty, value_ty); | 2993 | try self.store(ptr, .{ .register = tmp_reg }, ptr_ty, value_ty); |
| 2970 | } else { | 2994 | } else { |
| 2971 | return self.fail("TODO implement memcpy", .{}); | 2995 | const regs = try self.register_manager.allocRegs(4, .{ null, null, null, null }, gp); |
| | 2996 | const regs_locks = self.register_manager.lockRegsAssumeUnused(4, regs); |
| | 2997 | defer for (regs_locks) |reg| { |
| | 2998 | self.register_manager.unlockReg(reg); |
| | 2999 | }; |
| | 3000 | |
| | 3001 | const src_reg = addr_reg; |
| | 3002 | const dst_reg = regs[0]; |
| | 3003 | const len_reg = regs[1]; |
| | 3004 | const count_reg = regs[2]; |
| | 3005 | const tmp_reg = regs[3]; |
| | 3006 | |
| | 3007 | switch (value) { |
| | 3008 | .stack_offset => |off| { |
| | 3009 | // sub src_reg, fp, #off |
| | 3010 | try self.genSetReg(ptr_ty, src_reg, .{ .ptr_stack_offset = off }); |
| | 3011 | }, |
| | 3012 | .memory => |addr| try self.genSetReg(Type.usize, src_reg, .{ .immediate = @intCast(u32, addr) }), |
| | 3013 | .stack_argument_offset => |off| { |
| | 3014 | _ = try self.addInst(.{ |
| | 3015 | .tag = .ldr_ptr_stack_argument, |
| | 3016 | .data = .{ .load_store_stack = .{ |
| | 3017 | .rt = src_reg, |
| | 3018 | .offset = off, |
| | 3019 | } }, |
| | 3020 | }); |
| | 3021 | }, |
| | 3022 | else => return self.fail("TODO store {} to register", .{value}), |
| | 3023 | } |
| | 3024 | |
| | 3025 | // mov len, #abi_size |
| | 3026 | try self.genSetReg(Type.usize, len_reg, .{ .immediate = abi_size }); |
| | 3027 | |
| | 3028 | // memcpy(src, dst, len) |
| | 3029 | try self.genInlineMemcpy(src_reg, dst_reg, len_reg, count_reg, tmp_reg); |
| 2972 | } | 3030 | } |
| 2973 | }, | 3031 | }, |
| 2974 | } | 3032 | } |
| ... | @@ -4359,6 +4417,8 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void | ... | @@ -4359,6 +4417,8 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void |
| 4359 | } | 4417 | } |
| 4360 | }, | 4418 | }, |
| 4361 | .register => |src_reg| { | 4419 | .register => |src_reg| { |
| | 4420 | assert(src_reg.size() == reg.size()); |
| | 4421 | |
| 4362 | // If the registers are the same, nothing to do. | 4422 | // If the registers are the same, nothing to do. |
| 4363 | if (src_reg.id() == reg.id()) | 4423 | if (src_reg.id() == reg.id()) |
| 4364 | return; | 4424 | return; |