diff options
| author | Cody Tapscott <topolarity@tapscott.me> | 2022-02-13 15:04:46 -0700 |
|---|---|---|
| committer | Cody Tapscott <topolarity@tapscott.me> | 2022-02-18 14:28:32 -0700 |
| commit | ef417f19e147ebfa46035dac5ad800723c8fed94 (patch) | |
| tree | 147e7ec763440694c208a482b38f25c08b2b9de9 /src/codegen | |
| parent | dee96e2e2f464c3b8edc8ec3a63cd3b1860e3a9d (diff) | |
| download | zig-ef417f19e147ebfa46035dac5ad800723c8fed94.tar.gz zig-ef417f19e147ebfa46035dac5ad800723c8fed94.zip | |
stage2: Implement `@bitReverse` and `@byteSwap`
This change implements the above built-ins for Sema and the LLVM
backend. Other backends have had placeholders added for lowering.
Diffstat (limited to 'src/codegen')
| -rw-r--r-- | src/codegen/c.zig | 2 | ||||
| -rw-r--r-- | src/codegen/llvm.zig | 46 |
2 files changed, 45 insertions, 3 deletions
diff --git a/src/codegen/c.zig b/src/codegen/c.zig index 0391fa4c84..5fd3bd92ca 100644 --- a/src/codegen/c.zig +++ b/src/codegen/c.zig @@ -1709,6 +1709,8 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO .clz => try airBuiltinCall(f, inst, "clz"), .ctz => try airBuiltinCall(f, inst, "ctz"), .popcount => try airBuiltinCall(f, inst, "popcount"), + .byte_swap => try airBuiltinCall(f, inst, "byte_swap"), + .bit_reverse => try airBuiltinCall(f, inst, "bit_reverse"), .tag_name => try airTagName(f, inst), .error_name => try airErrorName(f, inst), .splat => try airSplat(f, inst), diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 3d65829c1e..05e377864b 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -2205,7 +2205,9 @@ pub const FuncGen = struct { .get_union_tag => try self.airGetUnionTag(inst), .clz => try self.airClzCtz(inst, "llvm.ctlz"), .ctz => try self.airClzCtz(inst, "llvm.cttz"), - .popcount => try self.airPopCount(inst), + .popcount => try self.airBitOp(inst, "llvm.ctpop"), + .byte_swap => try self.airByteSwap(inst, "llvm.bswap"), + .bit_reverse => try self.airBitOp(inst, "llvm.bitreverse"), .tag_name => try self.airTagName(inst), .error_name => try self.airErrorName(inst), .splat => try self.airSplat(inst), @@ -4348,7 +4350,7 @@ pub const FuncGen = struct { } } - fn airPopCount(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { + fn airBitOp(self: *FuncGen, inst: Air.Inst.Index, llvm_fn_name: []const u8) !?*const llvm.Value { if (self.liveness.isUnused(inst)) return null; const ty_op = self.air.instructions.items(.data)[inst].ty_op; @@ -4357,7 +4359,7 @@ pub const FuncGen = struct { const params = [_]*const llvm.Value{operand}; const operand_llvm_ty = try self.dg.llvmType(operand_ty); - const fn_val = self.getIntrinsic("llvm.ctpop", &.{operand_llvm_ty}); + const fn_val = self.getIntrinsic(llvm_fn_name, &.{operand_llvm_ty}); const wrong_size_result = self.builder.buildCall(fn_val, ¶ms, params.len, .C, .Auto, ""); const result_ty = self.air.typeOfIndex(inst); @@ -4375,6 +4377,44 @@ pub const FuncGen = struct { } } + fn airByteSwap(self: *FuncGen, inst: Air.Inst.Index, llvm_fn_name: []const u8) !?*const llvm.Value { + if (self.liveness.isUnused(inst)) return null; + + const target = self.dg.module.getTarget(); + const ty_op = self.air.instructions.items(.data)[inst].ty_op; + const operand_ty = self.air.typeOf(ty_op.operand); + var bits = operand_ty.intInfo(target).bits; + assert(bits % 8 == 0); + + var operand = try self.resolveInst(ty_op.operand); + var operand_llvm_ty = try self.dg.llvmType(operand_ty); + + if (bits % 16 == 8) { + // If not an even byte-multiple, we need zero-extend + shift-left 1 byte + // The truncated result at the end will be the correct bswap + operand_llvm_ty = self.context.intType(bits + 8); + const extended = self.builder.buildZExt(operand, operand_llvm_ty, ""); + operand = self.builder.buildShl(extended, operand_llvm_ty.constInt(8, .False), ""); + bits = bits + 8; + } + + const params = [_]*const llvm.Value{operand}; + const fn_val = self.getIntrinsic(llvm_fn_name, &.{operand_llvm_ty}); + + const wrong_size_result = self.builder.buildCall(fn_val, ¶ms, params.len, .C, .Auto, ""); + + const result_ty = self.air.typeOfIndex(inst); + const result_llvm_ty = try self.dg.llvmType(result_ty); + const result_bits = result_ty.intInfo(target).bits; + if (bits > result_bits) { + return self.builder.buildTrunc(wrong_size_result, result_llvm_ty, ""); + } else if (bits < result_bits) { + return self.builder.buildZExt(wrong_size_result, result_llvm_ty, ""); + } else { + return wrong_size_result; + } + } + fn airTagName(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { if (self.liveness.isUnused(inst)) return null; |
