| ... | ... | @@ -3960,10 +3960,11 @@ pub const FuncGen = struct { |
| 3960 | 3960 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 3961 | 3961 | const operand = try self.resolveInst(ty_op.operand); |
| 3962 | 3962 | const operand_ty = self.air.typeOf(ty_op.operand); |
| 3963 | const operand_scalar_ty = operand_ty.scalarType(); |
| 3963 | 3964 | const dest_ty = self.air.typeOfIndex(inst); |
| 3964 | 3965 | const dest_llvm_ty = try self.dg.llvmType(dest_ty); |
| 3965 | 3966 | |
| 3966 | | if (operand_ty.isSignedInt()) { |
| 3967 | if (operand_scalar_ty.isSignedInt()) { |
| 3967 | 3968 | return self.builder.buildSIToFP(operand, dest_llvm_ty, ""); |
| 3968 | 3969 | } else { |
| 3969 | 3970 | return self.builder.buildUIToFP(operand, dest_llvm_ty, ""); |
| ... | ... | @@ -3977,11 +3978,12 @@ pub const FuncGen = struct { |
| 3977 | 3978 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 3978 | 3979 | const operand = try self.resolveInst(ty_op.operand); |
| 3979 | 3980 | const dest_ty = self.air.typeOfIndex(inst); |
| 3981 | const dest_scalar_ty = dest_ty.scalarType(); |
| 3980 | 3982 | const dest_llvm_ty = try self.dg.llvmType(dest_ty); |
| 3981 | 3983 | |
| 3982 | 3984 | // TODO set fast math flag |
| 3983 | 3985 | |
| 3984 | | if (dest_ty.isSignedInt()) { |
| 3986 | if (dest_scalar_ty.isSignedInt()) { |
| 3985 | 3987 | return self.builder.buildFPToSI(operand, dest_llvm_ty, ""); |
| 3986 | 3988 | } else { |
| 3987 | 3989 | return self.builder.buildFPToUI(operand, dest_llvm_ty, ""); |
| ... | ... | @@ -4912,9 +4914,10 @@ pub const FuncGen = struct { |
| 4912 | 4914 | const lhs = try self.resolveInst(bin_op.lhs); |
| 4913 | 4915 | const rhs = try self.resolveInst(bin_op.rhs); |
| 4914 | 4916 | const inst_ty = self.air.typeOfIndex(inst); |
| 4917 | const scalar_ty = inst_ty.scalarType(); |
| 4915 | 4918 | |
| 4916 | | if (inst_ty.isAnyFloat()) return self.builder.buildFAdd(lhs, rhs, ""); |
| 4917 | | if (inst_ty.isSignedInt()) return self.builder.buildNSWAdd(lhs, rhs, ""); |
| 4919 | if (scalar_ty.isAnyFloat()) return self.builder.buildFAdd(lhs, rhs, ""); |
| 4920 | if (scalar_ty.isSignedInt()) return self.builder.buildNSWAdd(lhs, rhs, ""); |
| 4918 | 4921 | return self.builder.buildNUWAdd(lhs, rhs, ""); |
| 4919 | 4922 | } |
| 4920 | 4923 | |
| ... | ... | @@ -4935,9 +4938,10 @@ pub const FuncGen = struct { |
| 4935 | 4938 | const lhs = try self.resolveInst(bin_op.lhs); |
| 4936 | 4939 | const rhs = try self.resolveInst(bin_op.rhs); |
| 4937 | 4940 | const inst_ty = self.air.typeOfIndex(inst); |
| 4941 | const scalar_ty = inst_ty.scalarType(); |
| 4938 | 4942 | |
| 4939 | | if (inst_ty.isAnyFloat()) return self.todo("saturating float add", .{}); |
| 4940 | | if (inst_ty.isSignedInt()) return self.builder.buildSAddSat(lhs, rhs, ""); |
| 4943 | if (scalar_ty.isAnyFloat()) return self.todo("saturating float add", .{}); |
| 4944 | if (scalar_ty.isSignedInt()) return self.builder.buildSAddSat(lhs, rhs, ""); |
| 4941 | 4945 | |
| 4942 | 4946 | return self.builder.buildUAddSat(lhs, rhs, ""); |
| 4943 | 4947 | } |
| ... | ... | @@ -4949,9 +4953,10 @@ pub const FuncGen = struct { |
| 4949 | 4953 | const lhs = try self.resolveInst(bin_op.lhs); |
| 4950 | 4954 | const rhs = try self.resolveInst(bin_op.rhs); |
| 4951 | 4955 | const inst_ty = self.air.typeOfIndex(inst); |
| 4956 | const scalar_ty = inst_ty.scalarType(); |
| 4952 | 4957 | |
| 4953 | | if (inst_ty.isAnyFloat()) return self.builder.buildFSub(lhs, rhs, ""); |
| 4954 | | if (inst_ty.isSignedInt()) return self.builder.buildNSWSub(lhs, rhs, ""); |
| 4958 | if (scalar_ty.isAnyFloat()) return self.builder.buildFSub(lhs, rhs, ""); |
| 4959 | if (scalar_ty.isSignedInt()) return self.builder.buildNSWSub(lhs, rhs, ""); |
| 4955 | 4960 | return self.builder.buildNUWSub(lhs, rhs, ""); |
| 4956 | 4961 | } |
| 4957 | 4962 | |
| ... | ... | @@ -4972,9 +4977,10 @@ pub const FuncGen = struct { |
| 4972 | 4977 | const lhs = try self.resolveInst(bin_op.lhs); |
| 4973 | 4978 | const rhs = try self.resolveInst(bin_op.rhs); |
| 4974 | 4979 | const inst_ty = self.air.typeOfIndex(inst); |
| 4980 | const scalar_ty = inst_ty.scalarType(); |
| 4975 | 4981 | |
| 4976 | | if (inst_ty.isAnyFloat()) return self.todo("saturating float sub", .{}); |
| 4977 | | if (inst_ty.isSignedInt()) return self.builder.buildSSubSat(lhs, rhs, ""); |
| 4982 | if (scalar_ty.isAnyFloat()) return self.todo("saturating float sub", .{}); |
| 4983 | if (scalar_ty.isSignedInt()) return self.builder.buildSSubSat(lhs, rhs, ""); |
| 4978 | 4984 | return self.builder.buildUSubSat(lhs, rhs, ""); |
| 4979 | 4985 | } |
| 4980 | 4986 | |
| ... | ... | @@ -4985,9 +4991,10 @@ pub const FuncGen = struct { |
| 4985 | 4991 | const lhs = try self.resolveInst(bin_op.lhs); |
| 4986 | 4992 | const rhs = try self.resolveInst(bin_op.rhs); |
| 4987 | 4993 | const inst_ty = self.air.typeOfIndex(inst); |
| 4994 | const scalar_ty = inst_ty.scalarType(); |
| 4988 | 4995 | |
| 4989 | | if (inst_ty.isAnyFloat()) return self.builder.buildFMul(lhs, rhs, ""); |
| 4990 | | if (inst_ty.isSignedInt()) return self.builder.buildNSWMul(lhs, rhs, ""); |
| 4996 | if (scalar_ty.isAnyFloat()) return self.builder.buildFMul(lhs, rhs, ""); |
| 4997 | if (scalar_ty.isSignedInt()) return self.builder.buildNSWMul(lhs, rhs, ""); |
| 4991 | 4998 | return self.builder.buildNUWMul(lhs, rhs, ""); |
| 4992 | 4999 | } |
| 4993 | 5000 | |
| ... | ... | @@ -5008,9 +5015,10 @@ pub const FuncGen = struct { |
| 5008 | 5015 | const lhs = try self.resolveInst(bin_op.lhs); |
| 5009 | 5016 | const rhs = try self.resolveInst(bin_op.rhs); |
| 5010 | 5017 | const inst_ty = self.air.typeOfIndex(inst); |
| 5018 | const scalar_ty = inst_ty.scalarType(); |
| 5011 | 5019 | |
| 5012 | | if (inst_ty.isAnyFloat()) return self.todo("saturating float mul", .{}); |
| 5013 | | if (inst_ty.isSignedInt()) return self.builder.buildSMulFixSat(lhs, rhs, ""); |
| 5020 | if (scalar_ty.isAnyFloat()) return self.todo("saturating float mul", .{}); |
| 5021 | if (scalar_ty.isSignedInt()) return self.builder.buildSMulFixSat(lhs, rhs, ""); |
| 5014 | 5022 | return self.builder.buildUMulFixSat(lhs, rhs, ""); |
| 5015 | 5023 | } |
| 5016 | 5024 | |
| ... | ... | @@ -5031,12 +5039,13 @@ pub const FuncGen = struct { |
| 5031 | 5039 | const lhs = try self.resolveInst(bin_op.lhs); |
| 5032 | 5040 | const rhs = try self.resolveInst(bin_op.rhs); |
| 5033 | 5041 | const inst_ty = self.air.typeOfIndex(inst); |
| 5042 | const scalar_ty = inst_ty.scalarType(); |
| 5034 | 5043 | |
| 5035 | | if (inst_ty.isRuntimeFloat()) { |
| 5044 | if (scalar_ty.isRuntimeFloat()) { |
| 5036 | 5045 | const result = self.builder.buildFDiv(lhs, rhs, ""); |
| 5037 | 5046 | return self.callTrunc(result, inst_ty); |
| 5038 | 5047 | } |
| 5039 | | if (inst_ty.isSignedInt()) return self.builder.buildSDiv(lhs, rhs, ""); |
| 5048 | if (scalar_ty.isSignedInt()) return self.builder.buildSDiv(lhs, rhs, ""); |
| 5040 | 5049 | return self.builder.buildUDiv(lhs, rhs, ""); |
| 5041 | 5050 | } |
| 5042 | 5051 | |
| ... | ... | @@ -5047,12 +5056,13 @@ pub const FuncGen = struct { |
| 5047 | 5056 | const lhs = try self.resolveInst(bin_op.lhs); |
| 5048 | 5057 | const rhs = try self.resolveInst(bin_op.rhs); |
| 5049 | 5058 | const inst_ty = self.air.typeOfIndex(inst); |
| 5059 | const scalar_ty = inst_ty.scalarType(); |
| 5050 | 5060 | |
| 5051 | | if (inst_ty.isRuntimeFloat()) { |
| 5061 | if (scalar_ty.isRuntimeFloat()) { |
| 5052 | 5062 | const result = self.builder.buildFDiv(lhs, rhs, ""); |
| 5053 | 5063 | return try self.callFloor(result, inst_ty); |
| 5054 | 5064 | } |
| 5055 | | if (inst_ty.isSignedInt()) { |
| 5065 | if (scalar_ty.isSignedInt()) { |
| 5056 | 5066 | // const d = @divTrunc(a, b); |
| 5057 | 5067 | // const r = @rem(a, b); |
| 5058 | 5068 | // return if (r == 0) d else d - ((a < 0) ^ (b < 0)); |
| ... | ... | @@ -5078,9 +5088,10 @@ pub const FuncGen = struct { |
| 5078 | 5088 | const lhs = try self.resolveInst(bin_op.lhs); |
| 5079 | 5089 | const rhs = try self.resolveInst(bin_op.rhs); |
| 5080 | 5090 | const inst_ty = self.air.typeOfIndex(inst); |
| 5091 | const scalar_ty = inst_ty.scalarType(); |
| 5081 | 5092 | |
| 5082 | | if (inst_ty.isRuntimeFloat()) return self.builder.buildFDiv(lhs, rhs, ""); |
| 5083 | | if (inst_ty.isSignedInt()) return self.builder.buildExactSDiv(lhs, rhs, ""); |
| 5093 | if (scalar_ty.isRuntimeFloat()) return self.builder.buildFDiv(lhs, rhs, ""); |
| 5094 | if (scalar_ty.isSignedInt()) return self.builder.buildExactSDiv(lhs, rhs, ""); |
| 5084 | 5095 | return self.builder.buildExactUDiv(lhs, rhs, ""); |
| 5085 | 5096 | } |
| 5086 | 5097 | |
| ... | ... | @@ -5091,9 +5102,10 @@ pub const FuncGen = struct { |
| 5091 | 5102 | const lhs = try self.resolveInst(bin_op.lhs); |
| 5092 | 5103 | const rhs = try self.resolveInst(bin_op.rhs); |
| 5093 | 5104 | const inst_ty = self.air.typeOfIndex(inst); |
| 5105 | const scalar_ty = inst_ty.scalarType(); |
| 5094 | 5106 | |
| 5095 | | if (inst_ty.isRuntimeFloat()) return self.builder.buildFRem(lhs, rhs, ""); |
| 5096 | | if (inst_ty.isSignedInt()) return self.builder.buildSRem(lhs, rhs, ""); |
| 5107 | if (scalar_ty.isRuntimeFloat()) return self.builder.buildFRem(lhs, rhs, ""); |
| 5108 | if (scalar_ty.isSignedInt()) return self.builder.buildSRem(lhs, rhs, ""); |
| 5097 | 5109 | return self.builder.buildURem(lhs, rhs, ""); |
| 5098 | 5110 | } |
| 5099 | 5111 | |
| ... | ... | @@ -5105,8 +5117,9 @@ pub const FuncGen = struct { |
| 5105 | 5117 | const rhs = try self.resolveInst(bin_op.rhs); |
| 5106 | 5118 | const inst_ty = self.air.typeOfIndex(inst); |
| 5107 | 5119 | const inst_llvm_ty = try self.dg.llvmType(inst_ty); |
| 5120 | const scalar_ty = inst_ty.scalarType(); |
| 5108 | 5121 | |
| 5109 | | if (inst_ty.isRuntimeFloat()) { |
| 5122 | if (scalar_ty.isRuntimeFloat()) { |
| 5110 | 5123 | const a = self.builder.buildFRem(lhs, rhs, ""); |
| 5111 | 5124 | const b = self.builder.buildFAdd(a, rhs, ""); |
| 5112 | 5125 | const c = self.builder.buildFRem(b, rhs, ""); |
| ... | ... | @@ -5114,7 +5127,7 @@ pub const FuncGen = struct { |
| 5114 | 5127 | const ltz = self.builder.buildFCmp(.OLT, lhs, zero, ""); |
| 5115 | 5128 | return self.builder.buildSelect(ltz, c, a, ""); |
| 5116 | 5129 | } |
| 5117 | | if (inst_ty.isSignedInt()) { |
| 5130 | if (scalar_ty.isSignedInt()) { |
| 5118 | 5131 | const a = self.builder.buildSRem(lhs, rhs, ""); |
| 5119 | 5132 | const b = self.builder.buildNSWAdd(a, rhs, ""); |
| 5120 | 5133 | const c = self.builder.buildSRem(b, rhs, ""); |
| ... | ... | @@ -5339,15 +5352,22 @@ pub const FuncGen = struct { |
| 5339 | 5352 | if (self.liveness.isUnused(inst)) return null; |
| 5340 | 5353 | |
| 5341 | 5354 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 5355 | |
| 5342 | 5356 | const lhs = try self.resolveInst(bin_op.lhs); |
| 5343 | 5357 | const rhs = try self.resolveInst(bin_op.rhs); |
| 5344 | | const lhs_type = self.air.typeOf(bin_op.lhs); |
| 5358 | |
| 5359 | const lhs_ty = self.air.typeOf(bin_op.lhs); |
| 5360 | const rhs_ty = self.air.typeOf(bin_op.rhs); |
| 5361 | const lhs_scalar_ty = lhs_ty.scalarType(); |
| 5362 | const rhs_scalar_ty = rhs_ty.scalarType(); |
| 5363 | |
| 5345 | 5364 | const tg = self.dg.module.getTarget(); |
| 5346 | | const casted_rhs = if (self.air.typeOf(bin_op.rhs).bitSize(tg) < lhs_type.bitSize(tg)) |
| 5347 | | self.builder.buildZExt(rhs, try self.dg.llvmType(lhs_type), "") |
| 5365 | |
| 5366 | const casted_rhs = if (rhs_scalar_ty.bitSize(tg) < lhs_scalar_ty.bitSize(tg)) |
| 5367 | self.builder.buildZExt(rhs, try self.dg.llvmType(lhs_ty), "") |
| 5348 | 5368 | else |
| 5349 | 5369 | rhs; |
| 5350 | | if (lhs_type.isSignedInt()) return self.builder.buildNSWShl(lhs, casted_rhs, ""); |
| 5370 | if (lhs_scalar_ty.isSignedInt()) return self.builder.buildNSWShl(lhs, casted_rhs, ""); |
| 5351 | 5371 | return self.builder.buildNUWShl(lhs, casted_rhs, ""); |
| 5352 | 5372 | } |
| 5353 | 5373 | |
| ... | ... | @@ -5355,11 +5375,18 @@ pub const FuncGen = struct { |
| 5355 | 5375 | if (self.liveness.isUnused(inst)) return null; |
| 5356 | 5376 | |
| 5357 | 5377 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 5378 | |
| 5358 | 5379 | const lhs = try self.resolveInst(bin_op.lhs); |
| 5359 | 5380 | const rhs = try self.resolveInst(bin_op.rhs); |
| 5381 | |
| 5360 | 5382 | const lhs_type = self.air.typeOf(bin_op.lhs); |
| 5383 | const rhs_type = self.air.typeOf(bin_op.rhs); |
| 5384 | const lhs_scalar_ty = lhs_type.scalarType(); |
| 5385 | const rhs_scalar_ty = rhs_type.scalarType(); |
| 5386 | |
| 5361 | 5387 | const tg = self.dg.module.getTarget(); |
| 5362 | | const casted_rhs = if (self.air.typeOf(bin_op.rhs).bitSize(tg) < lhs_type.bitSize(tg)) |
| 5388 | |
| 5389 | const casted_rhs = if (rhs_scalar_ty.bitSize(tg) < lhs_scalar_ty.bitSize(tg)) |
| 5363 | 5390 | self.builder.buildZExt(rhs, try self.dg.llvmType(lhs_type), "") |
| 5364 | 5391 | else |
| 5365 | 5392 | rhs; |
| ... | ... | @@ -5370,31 +5397,45 @@ pub const FuncGen = struct { |
| 5370 | 5397 | if (self.liveness.isUnused(inst)) return null; |
| 5371 | 5398 | |
| 5372 | 5399 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 5400 | |
| 5373 | 5401 | const lhs = try self.resolveInst(bin_op.lhs); |
| 5374 | 5402 | const rhs = try self.resolveInst(bin_op.rhs); |
| 5375 | | const lhs_type = self.air.typeOf(bin_op.lhs); |
| 5403 | |
| 5404 | const lhs_ty = self.air.typeOf(bin_op.lhs); |
| 5405 | const rhs_ty = self.air.typeOf(bin_op.rhs); |
| 5406 | const lhs_scalar_ty = lhs_ty.scalarType(); |
| 5407 | const rhs_scalar_ty = rhs_ty.scalarType(); |
| 5408 | |
| 5376 | 5409 | const tg = self.dg.module.getTarget(); |
| 5377 | | const casted_rhs = if (self.air.typeOf(bin_op.rhs).bitSize(tg) < lhs_type.bitSize(tg)) |
| 5378 | | self.builder.buildZExt(rhs, try self.dg.llvmType(lhs_type), "") |
| 5410 | |
| 5411 | const casted_rhs = if (rhs_scalar_ty.bitSize(tg) < lhs_scalar_ty.bitSize(tg)) |
| 5412 | self.builder.buildZExt(rhs, try self.dg.llvmType(lhs_ty), "") |
| 5379 | 5413 | else |
| 5380 | 5414 | rhs; |
| 5381 | | if (lhs_type.isSignedInt()) return self.builder.buildSShlSat(lhs, casted_rhs, ""); |
| 5415 | if (lhs_scalar_ty.isSignedInt()) return self.builder.buildSShlSat(lhs, casted_rhs, ""); |
| 5382 | 5416 | return self.builder.buildUShlSat(lhs, casted_rhs, ""); |
| 5383 | 5417 | } |
| 5384 | 5418 | |
| 5385 | 5419 | fn airShr(self: *FuncGen, inst: Air.Inst.Index, is_exact: bool) !?*const llvm.Value { |
| 5386 | | if (self.liveness.isUnused(inst)) |
| 5387 | | return null; |
| 5420 | if (self.liveness.isUnused(inst)) return null; |
| 5421 | |
| 5388 | 5422 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 5423 | |
| 5389 | 5424 | const lhs = try self.resolveInst(bin_op.lhs); |
| 5390 | 5425 | const rhs = try self.resolveInst(bin_op.rhs); |
| 5391 | | const lhs_type = self.air.typeOf(bin_op.lhs); |
| 5426 | |
| 5427 | const lhs_ty = self.air.typeOf(bin_op.lhs); |
| 5428 | const rhs_ty = self.air.typeOf(bin_op.rhs); |
| 5429 | const lhs_scalar_ty = lhs_ty.scalarType(); |
| 5430 | const rhs_scalar_ty = rhs_ty.scalarType(); |
| 5431 | |
| 5392 | 5432 | const tg = self.dg.module.getTarget(); |
| 5393 | | const casted_rhs = if (self.air.typeOf(bin_op.rhs).bitSize(tg) < lhs_type.bitSize(tg)) |
| 5394 | | self.builder.buildZExt(rhs, try self.dg.llvmType(lhs_type), "") |
| 5433 | |
| 5434 | const casted_rhs = if (rhs_scalar_ty.bitSize(tg) < lhs_scalar_ty.bitSize(tg)) |
| 5435 | self.builder.buildZExt(rhs, try self.dg.llvmType(lhs_ty), "") |
| 5395 | 5436 | else |
| 5396 | 5437 | rhs; |
| 5397 | | const is_signed_int = self.air.typeOfIndex(inst).isSignedInt(); |
| 5438 | const is_signed_int = lhs_scalar_ty.isSignedInt(); |
| 5398 | 5439 | |
| 5399 | 5440 | if (is_exact) { |
| 5400 | 5441 | if (is_signed_int) { |