https://github.com/patricklapgar updated https://github.com/llvm/llvm-project/pull/216899
>From 72ecc7caedba6ab9e30c3d0639519506349ec69b Mon Sep 17 00:00:00 2001 From: patricklapgar <[email protected]> Date: Mon, 17 Aug 2026 18:54:00 -0700 Subject: [PATCH 1/6] Add tr instruction intrinsic def --- llvm/include/llvm/IR/IntrinsicsSystemZ.td | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/llvm/include/llvm/IR/IntrinsicsSystemZ.td b/llvm/include/llvm/IR/IntrinsicsSystemZ.td index 38b7463c7b078..8e08a105c2d44 100644 --- a/llvm/include/llvm/IR/IntrinsicsSystemZ.td +++ b/llvm/include/llvm/IR/IntrinsicsSystemZ.td @@ -503,3 +503,10 @@ let TargetPrefix = "s390" in { Intrinsic<[llvm_i64_ty], [llvm_i64_ty, llvm_i64_ty], [IntrNoMem]>; } + +let TargetPrefix = "s390" in { + def int_s390_translate : Intrinsic<[], + [llvm_ptr_ty, llvm_ptr_ty, llvm_i32_ty], + [NoCapture<ArgIndex<0>>, NoCapture<ArgIndex<1>>]>, + ClangBuiltin<"__builtin_s390_tr">; +} \ No newline at end of file >From 7f7fdf953b62c47a7365b0338ed8067aa16d8e43 Mon Sep 17 00:00:00 2001 From: patricklapgar <[email protected]> Date: Mon, 17 Aug 2026 18:54:55 -0700 Subject: [PATCH 2/6] Support tr intrinsic handling pre-lowering --- .../Target/SystemZ/SystemZISelLowering.cpp | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp index 710832525426b..1f2db88bfd7a5 100644 --- a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp +++ b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp @@ -5444,6 +5444,39 @@ SDValue SystemZTargetLowering::lowerPREFETCH(SDValue Op, SDValue SystemZTargetLowering::lowerINTRINSIC_W_CHAIN(SDValue Op, SelectionDAG &DAG) const { + SDLoc DL(op); + unsigned IntNo = Op.getConstantOperandVal(1); + + // Intercept translation intrinsic + if (IntNo == Intrinsic::int_s390_translate) { + SDValue Chain = Op.getOperand(0); + SDValue Src = Op.getOperand(2); + SDValue Tbl = Op.getOperand(3); + SDValue Len = Op.getOperand(4); + + // If the input length is a static constant, + // create a new target node and return it + if(auto *ConstLen = dyn_cast<ConstantSDNode>(Len)) { + uint64_t Value = ConstLen->getZExtValue(); + + if(Value >= 1 && Value <= 256) { + uint64_t HardwareLen = Value - 1; + SDValue ImmLen = DAG.getTargetConstant(HardwareLen, DL, MVT::i32); + + SmallVector<SDValue, 4> Ops; + Ops.push_back(Chain); + Ops.push_back(Src); + Ops.push_back(ImmLen); + Ops.push_back(Tbl); + + return DAG.getNode(SystemZISD::TR, DL, MVT::Other, Ops); + } + } + + // If the input length is variable, return the SDValue as-is + return SDValue(); + } + unsigned Opcode, CCValid; if (isIntrinsicWithCCAndChain(Op, Opcode, CCValid)) { assert(Op->getNumValues() == 2 && "Expected only CC result and chain"); >From 309a4287d678e43e0fde9515dd9f3bb0db6295bd Mon Sep 17 00:00:00 2001 From: patricklapgar <[email protected]> Date: Mon, 17 Aug 2026 18:56:43 -0700 Subject: [PATCH 3/6] Support tr pseudo function and opcode pattern --- llvm/lib/Target/SystemZ/SystemZInstrInfo.td | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/llvm/lib/Target/SystemZ/SystemZInstrInfo.td b/llvm/lib/Target/SystemZ/SystemZInstrInfo.td index f53716a663ed8..e527916436ce2 100644 --- a/llvm/lib/Target/SystemZ/SystemZInstrInfo.td +++ b/llvm/lib/Target/SystemZ/SystemZInstrInfo.td @@ -1923,6 +1923,25 @@ let Predicates = [FeatureConcurrentFunctions], Uses = [R0D], Defs = [CC], def PFCR : BinaryRSY<"pfcr", 0xEB16, null_frag, GR64>; } +//===----------------------------------------------------------------------===// +// Translate +//===----------------------------------------------------------------------===// + +// Handle variable length data via pseudo +def TR_VAR + : Pseudo<(outs), (ins GR64:$src, GR64:$tbl, GR32:$len), + [(int_s390_translate GR64:$src, GR64:$tbl, GR32:$len)]> { + let hasSideEffects = 1; + let mayLoad = 1; + let mayStore = 1; + let Uses = [CC]; + let Defs = [CC]; +} + +// Handle constant length data by pattern matching directly to TR opcode +def : Pat<(z_tr GR64:$src, imm:$len, GR64:$tbl), + (TR GR64:$src, imm:$len, GR64:$tbl)>; + //===----------------------------------------------------------------------===// // Translate and convert //===----------------------------------------------------------------------===// >From 3638c14eae5f8ec59370a123588cd11f11ccfff1 Mon Sep 17 00:00:00 2001 From: patricklapgar <[email protected]> Date: Mon, 17 Aug 2026 18:57:28 -0700 Subject: [PATCH 4/6] Add SystemZ TR opcode def --- llvm/lib/Target/SystemZ/SystemZOperators.td | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/llvm/lib/Target/SystemZ/SystemZOperators.td b/llvm/lib/Target/SystemZ/SystemZOperators.td index 005b79638218a..75b708d0b66fb 100644 --- a/llvm/lib/Target/SystemZ/SystemZOperators.td +++ b/llvm/lib/Target/SystemZ/SystemZOperators.td @@ -257,6 +257,10 @@ def SDT_ZSetJmp : SDTypeProfile<1, 1, SDTCisPtrTy<1>]>; def SDT_ZLongJmp : SDTypeProfile<0, 1, [SDTCisPtrTy<0>]>; +def SDT_ZTranslate : SDTypeProfile<0, 3, + [SDTCisPtrTy<0>, + SDTCisInt<1>, + SDTCisPtrTy<2>]>; //===----------------------------------------------------------------------===// // Node definitions @@ -420,6 +424,10 @@ def z_storeeswap : SDNode<"SystemZISD::VSTER", SDTStore, def z_stckf : SDNode<"SystemZISD::STCKF", SDT_ZStoreInherent, [SDNPHasChain, SDNPMayStore, SDNPMemOperand]>; +// Translate string data from one code to another code +def z_tr : SDNode<"SystemZISD::TR", SDT_ZTranslate, + [SDNPHasChain, SDNPSideEffect, SDNPMayLoad, SDNPMayStore]>; + // Test Data Class. // // Operand 0: the value to test >From 9392cb5f539967cedf139b9b82e9eb070e4cf92a Mon Sep 17 00:00:00 2001 From: patricklapgar <[email protected]> Date: Mon, 31 Aug 2026 19:14:20 -0700 Subject: [PATCH 5/6] TR instruction source update (WIP) --- clang/include/clang/Basic/BuiltinsSystemZ.td | 5 ++ .../CodeGen/SystemZ/builtins-systemz-tr.c | 37 +++++++++ llvm/include/llvm/IR/IntrinsicsSystemZ.td | 6 +- .../Target/SystemZ/SystemZISelLowering.cpp | 76 +++++++++++-------- llvm/lib/Target/SystemZ/SystemZISelLowering.h | 4 + llvm/lib/Target/SystemZ/SystemZInstrInfo.td | 49 +++++++----- llvm/lib/Target/SystemZ/SystemZOperators.td | 14 ++-- .../CodeGen/SystemZ/translate-instruction.ll | 45 +++++++++++ 8 files changed, 176 insertions(+), 60 deletions(-) create mode 100644 clang/test/CodeGen/SystemZ/builtins-systemz-tr.c create mode 100644 llvm/test/CodeGen/SystemZ/translate-instruction.ll diff --git a/clang/include/clang/Basic/BuiltinsSystemZ.td b/clang/include/clang/Basic/BuiltinsSystemZ.td index 946a03cd66170..978bf4ca39af0 100644 --- a/clang/include/clang/Basic/BuiltinsSystemZ.td +++ b/clang/include/clang/Basic/BuiltinsSystemZ.td @@ -375,3 +375,8 @@ let Attributes = [NoThrow, Const], Features = "vector-enhancements-3" in { def vclzq : SystemZTargetBuiltin<"__uint128_t(__uint128_t)">; def vctzq : SystemZTargetBuiltin<"__uint128_t(__uint128_t)">; } + +// String/General memory intrinsics +let Attributes = [NoThrow] in { + def tr : SystemZTargetBuiltin<"void(void *, int, int, void *, int)">; +} \ No newline at end of file diff --git a/clang/test/CodeGen/SystemZ/builtins-systemz-tr.c b/clang/test/CodeGen/SystemZ/builtins-systemz-tr.c new file mode 100644 index 0000000000000..18d78c6ca1391 --- /dev/null +++ b/clang/test/CodeGen/SystemZ/builtins-systemz-tr.c @@ -0,0 +1,37 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 6 +// RUN: %clang_cc1 -triple s390x-linux-gnu -target-cpu z13 -emit-llvm %s -o - | FileCheck %s + +// CHECK-LABEL: define dso_local void @test_tr_static( +// CHECK-SAME: ptr noundef [[SRC:%.*]], ptr noundef [[TBL:%.*]]) #[[ATTR0:[0-9]+]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[SRC_ADDR:%.*]] = alloca ptr, align 8 +// CHECK-NEXT: [[TBL_ADDR:%.*]] = alloca ptr, align 8 +// CHECK-NEXT: store ptr [[SRC]], ptr [[SRC_ADDR]], align 8 +// CHECK-NEXT: store ptr [[TBL]], ptr [[TBL_ADDR]], align 8 +// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[SRC_ADDR]], align 8 +// CHECK-NEXT: [[TMP1:%.*]] = load ptr, ptr [[TBL_ADDR]], align 8 +// CHECK-NEXT: call void @llvm.s390.translate(ptr [[TMP0]], i32 0, i32 16, ptr [[TMP1]], i32 0) +// CHECK-NEXT: ret void +// +void test_tr_static(char *src, char *tbl) { + __builtin_s390_tr(src, 0, 16, tbl, 0); +} + +// CHECK-LABEL: define dso_local void @test_tr_variable( +// CHECK-SAME: ptr noundef [[SRC:%.*]], ptr noundef [[TBL:%.*]], i32 noundef signext [[LEN:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[SRC_ADDR:%.*]] = alloca ptr, align 8 +// CHECK-NEXT: [[TBL_ADDR:%.*]] = alloca ptr, align 8 +// CHECK-NEXT: [[LEN_ADDR:%.*]] = alloca i32, align 4 +// CHECK-NEXT: store ptr [[SRC]], ptr [[SRC_ADDR]], align 8 +// CHECK-NEXT: store ptr [[TBL]], ptr [[TBL_ADDR]], align 8 +// CHECK-NEXT: store i32 [[LEN]], ptr [[LEN_ADDR]], align 4 +// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[SRC_ADDR]], align 8 +// CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[LEN_ADDR]], align 4 +// CHECK-NEXT: [[TMP2:%.*]] = load ptr, ptr [[TBL_ADDR]], align 8 +// CHECK-NEXT: call void @llvm.s390.translate(ptr [[TMP0]], i32 0, i32 [[TMP1]], ptr [[TMP2]], i32 0) +// CHECK-NEXT: ret void +// +void test_tr_variable(char *src, char *tbl, int len) { + __builtin_s390_tr(src, 0, len, tbl, 0); +} diff --git a/llvm/include/llvm/IR/IntrinsicsSystemZ.td b/llvm/include/llvm/IR/IntrinsicsSystemZ.td index 8e08a105c2d44..9d87202439053 100644 --- a/llvm/include/llvm/IR/IntrinsicsSystemZ.td +++ b/llvm/include/llvm/IR/IntrinsicsSystemZ.td @@ -506,7 +506,9 @@ let TargetPrefix = "s390" in { let TargetPrefix = "s390" in { def int_s390_translate : Intrinsic<[], - [llvm_ptr_ty, llvm_ptr_ty, llvm_i32_ty], - [NoCapture<ArgIndex<0>>, NoCapture<ArgIndex<1>>]>, + [llvm_ptr_ty, llvm_i32_ty, llvm_i32_ty, + llvm_ptr_ty, llvm_i32_ty], + [IntrArgMemOnly, + NoCapture<ArgIndex<0>>, NoCapture<ArgIndex<3>>]>, ClangBuiltin<"__builtin_s390_tr">; } \ No newline at end of file diff --git a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp index fd7eabb5fc555..5e8884fa52cfc 100644 --- a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp +++ b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp @@ -5444,39 +5444,7 @@ SDValue SystemZTargetLowering::lowerPREFETCH(SDValue Op, SDValue SystemZTargetLowering::lowerINTRINSIC_W_CHAIN(SDValue Op, SelectionDAG &DAG) const { - SDLoc DL(op); - unsigned IntNo = Op.getConstantOperandVal(1); - - // Intercept translation intrinsic - if (IntNo == Intrinsic::int_s390_translate) { - SDValue Chain = Op.getOperand(0); - SDValue Src = Op.getOperand(2); - SDValue Tbl = Op.getOperand(3); - SDValue Len = Op.getOperand(4); - - // If the input length is a static constant, - // create a new target node and return it - if(auto *ConstLen = dyn_cast<ConstantSDNode>(Len)) { - uint64_t Value = ConstLen->getZExtValue(); - - if(Value >= 1 && Value <= 256) { - uint64_t HardwareLen = Value - 1; - SDValue ImmLen = DAG.getTargetConstant(HardwareLen, DL, MVT::i32); - - SmallVector<SDValue, 4> Ops; - Ops.push_back(Chain); - Ops.push_back(Src); - Ops.push_back(ImmLen); - Ops.push_back(Tbl); - - return DAG.getNode(SystemZISD::TR, DL, MVT::Other, Ops); - } - } - - // If the input length is variable, return the SDValue as-is - return SDValue(); - } - + SDLoc DL(Op); unsigned Opcode, CCValid; if (isIntrinsicWithCCAndChain(Op, Opcode, CCValid)) { assert(Op->getNumValues() == 2 && "Expected only CC result and chain"); @@ -10556,6 +10524,45 @@ MachineBasicBlock *SystemZTargetLowering::emitExt128(MachineInstr &MI, return MBB; } +MachineBasicBlock * +SystemZTargetLowering::emitTRWrapper(MachineInstr &MI, + MachineBasicBlock *MBB, + unsigned Opcode) const { + MachineFunction &MF = *MBB->getParent(); + MachineRegisterInfo &MRI = MF.getRegInfo(); + const SystemZInstrInfo *TII = + static_cast<const SystemZInstrInfo *>(Subtarget.getInstrInfo()); + DebugLoc DL = MI.getDebugLoc(); + + Register SrcReg = MI.getOperand(0).getReg(); + int64_t D1Imm = MI.getOperand(1).getImm(); + Register LenReg = MI.getOperand(2).getReg(); + Register TblReg = MI.getOperand(3).getReg(); + int64_t D2Imm = MI.getOperand(4).getImm(); + + MRI.constrainRegClass(SrcReg, &SystemZ::ADDR64BitRegClass); + MRI.constrainRegClass(TblReg, &SystemZ::ADDR64BitRegClass); + + Register Len32Reg = MRI.createVirtualRegister(&SystemZ::GR32BitRegClass); + BuildMI(*MBB, MI, DL, TII->get(SystemZ::AHI), Len32Reg) + .addReg(LenReg) + .addImm(-1); + + // Must constrain 32-bit length register to 64-bit for EXRL execution + Register Len64Reg = MRI.createVirtualRegister(&SystemZ::ADDR64BitRegClass); + BuildMI(*MBB, MI, DL, TII->get(SystemZ::LLGFR), Len64Reg) + .addReg(Len32Reg); + + BuildMI(*MBB, MI, DL, TII->get(SystemZ::EXRL_Pseudo)) + .addImm(Opcode) + .addReg(Len64Reg) + .addReg(SrcReg).addImm(D1Imm) + .addReg(TblReg).addImm(D2Imm); + + MI.eraseFromParent(); + return MBB; +} + MachineBasicBlock * SystemZTargetLowering::emitMemMemWrapper(MachineInstr &MI, MachineBasicBlock *MBB, @@ -11363,6 +11370,9 @@ MachineBasicBlock *SystemZTargetLowering::EmitInstrWithCustomInserter( case SystemZ::CMP_STACKGUARD_DAG: return emitStackGuardPseudo(MI, MBB, SystemZ::CMP_STACKGUARD); + case SystemZ::TR_Pseudo: + return emitTRWrapper(MI, MBB, SystemZ::TR); + default: llvm_unreachable("Unexpected instr type to insert"); } diff --git a/llvm/lib/Target/SystemZ/SystemZISelLowering.h b/llvm/lib/Target/SystemZ/SystemZISelLowering.h index f01f7dcc6ab1d..b7b27532f7e4d 100644 --- a/llvm/lib/Target/SystemZ/SystemZISelLowering.h +++ b/llvm/lib/Target/SystemZ/SystemZISelLowering.h @@ -494,6 +494,10 @@ class SystemZTargetLowering : public TargetLowering { getTargetMMOFlags(const Instruction &I) const override; const TargetRegisterClass *getRepRegClassFor(MVT VT) const override; + MachineBasicBlock *emitTRWrapper(MachineInstr &MI, + MachineBasicBlock *MBB, + unsigned Opcode) const; + private: bool isInternal(const Function *Fn) const; mutable std::map<const Function *, bool> IsInternalCache; diff --git a/llvm/lib/Target/SystemZ/SystemZInstrInfo.td b/llvm/lib/Target/SystemZ/SystemZInstrInfo.td index e527916436ce2..2784a58d00952 100644 --- a/llvm/lib/Target/SystemZ/SystemZInstrInfo.td +++ b/llvm/lib/Target/SystemZ/SystemZInstrInfo.td @@ -1923,25 +1923,6 @@ let Predicates = [FeatureConcurrentFunctions], Uses = [R0D], Defs = [CC], def PFCR : BinaryRSY<"pfcr", 0xEB16, null_frag, GR64>; } -//===----------------------------------------------------------------------===// -// Translate -//===----------------------------------------------------------------------===// - -// Handle variable length data via pseudo -def TR_VAR - : Pseudo<(outs), (ins GR64:$src, GR64:$tbl, GR32:$len), - [(int_s390_translate GR64:$src, GR64:$tbl, GR32:$len)]> { - let hasSideEffects = 1; - let mayLoad = 1; - let mayStore = 1; - let Uses = [CC]; - let Defs = [CC]; -} - -// Handle constant length data by pattern matching directly to TR opcode -def : Pat<(z_tr GR64:$src, imm:$len, GR64:$tbl), - (TR GR64:$src, imm:$len, GR64:$tbl)>; - //===----------------------------------------------------------------------===// // Translate and convert //===----------------------------------------------------------------------===// @@ -2290,6 +2271,36 @@ let hasSideEffects = 1 in { []>; } +// Translate +let hasSideEffects = 1, usesCustomInserter = 1, + hasNoSchedulingInfo = 1, mayLoad = 1, + mayStore = 1, Defs = [CC] in { + def TR_Pseudo : Pseudo<(outs), (ins GR64:$src, i32imm:$D1, GR32:$len, + GR64:$tbl, i32imm:$D2), []>; + // [(z_tr GR64:$src, i32imm:$D1, GR32:$len, + // GR64:$tbl, i32imm:$D2)]>; +} + +// Transform constant length N (1..256) into N - 1 for SS-format +def tr_len : SDNodeXForm<imm, [{ + return CurDAG->getTargetConstant(N->getZExtValue() - 1, SDLoc(N), MVT::i32); +}]>; + +def tr_len_leaf : ImmLeaf<i32, + [{ return N->getZExtValue() >= 1 && N->getZExtValue() <= 256; }], + tr_len +>; + +// Match TR invocation w/ a static constant provided as the length +def : Pat<(int_s390_translate ADDR64:$src, i32:$D1, tr_len_leaf:$len, + ADDR64:$tbl, i32:$D2), + (TR (bdladdr12onlylen8 ADDR64:$src, i32:$D1, tr_len_leaf:$len), + (bdaddr12only ADDR64:$tbl, i32:$D2))>; + +// Match TR invocation w/ a variable provided as the length +def : Pat<(int_s390_translate ADDR64:$src, i32:$D1, GR32:$len, GR64:$tbl, i32:$D2), + (TR_Pseudo ADDR64:$src, i32:$D1, GR32:$len, ADDR64:$tbl, i32:$D2)>; + //===----------------------------------------------------------------------===// // .insn directive instructions //===----------------------------------------------------------------------===// diff --git a/llvm/lib/Target/SystemZ/SystemZOperators.td b/llvm/lib/Target/SystemZ/SystemZOperators.td index 75b708d0b66fb..b0a5327d92c04 100644 --- a/llvm/lib/Target/SystemZ/SystemZOperators.td +++ b/llvm/lib/Target/SystemZ/SystemZOperators.td @@ -257,10 +257,12 @@ def SDT_ZSetJmp : SDTypeProfile<1, 1, SDTCisPtrTy<1>]>; def SDT_ZLongJmp : SDTypeProfile<0, 1, [SDTCisPtrTy<0>]>; -def SDT_ZTranslate : SDTypeProfile<0, 3, - [SDTCisPtrTy<0>, - SDTCisInt<1>, - SDTCisPtrTy<2>]>; +// def SDT_ZTranslate : SDTypeProfile<0, 5, +// [SDTCisPtrTy<0>, +// SDTCisInt<1>, +// SDTCisInt<2>, +// SDTCisPtrTy<3>, +// SDTCisInt<4>]>; //===----------------------------------------------------------------------===// // Node definitions @@ -425,8 +427,8 @@ def z_stckf : SDNode<"SystemZISD::STCKF", SDT_ZStoreInherent, [SDNPHasChain, SDNPMayStore, SDNPMemOperand]>; // Translate string data from one code to another code -def z_tr : SDNode<"SystemZISD::TR", SDT_ZTranslate, - [SDNPHasChain, SDNPSideEffect, SDNPMayLoad, SDNPMayStore]>; +// def z_tr : SDNode<"SystemZISD::TR", SDT_ZTranslate, +// [SDNPHasChain, SDNPMayLoad, SDNPMayStore]>; // Test Data Class. // diff --git a/llvm/test/CodeGen/SystemZ/translate-instruction.ll b/llvm/test/CodeGen/SystemZ/translate-instruction.ll new file mode 100644 index 0000000000000..8458875838e91 --- /dev/null +++ b/llvm/test/CodeGen/SystemZ/translate-instruction.ll @@ -0,0 +1,45 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6 +; RUN: llc < %s -mtriple=s390x-linux-gnu -mcpu=z13 -verify-machineinstrs | FileCheck %s + +declare void @llvm.s390.translate(ptr, i32, i32, ptr, i32) + +;Test 1: Static constant length -> Direct TR instruction +define void @test_tr_static(ptr %src, ptr %tbl) { +; CHECK-LABEL: test_tr_static: +; CHECK: # %bb.0: +; CHECK-NEXT: stmg %r6, %r15, 48(%r15) +; CHECK-NEXT: .cfi_offset %r6, -112 +; CHECK-NEXT: .cfi_offset %r14, -48 +; CHECK-NEXT: .cfi_offset %r15, -40 +; CHECK-NEXT: aghi %r15, -160 +; CHECK-NEXT: .cfi_def_cfa_offset 320 +; CHECK-NEXT: lgr %r5, %r3 +; CHECK-NEXT: lhi %r3, 0 +; CHECK-NEXT: lhi %r4, 16 +; CHECK-NEXT: lhi %r6, 0 +; CHECK-NEXT: brasl %r14, llvm.s390.translate@PLT +; CHECK-NEXT: lmg %r6, %r15, 208(%r15) +; CHECK-NEXT: br %r14 + call void @llvm.s390.translate(ptr %src, i32 0, i32 16, ptr %tbl, i32 0) + ret void +} + +; Test 2: Variable length -> AHI (decrement by 1) + EXRL execution +define void @test_tr_variable(ptr %src, ptr %tbl, i32 %len) { +; CHECK-LABEL: test_tr_variable: +; CHECK: # %bb.0: +; CHECK-NEXT: stmg %r6, %r15, 48(%r15) +; CHECK-NEXT: .cfi_offset %r6, -112 +; CHECK-NEXT: .cfi_offset %r14, -48 +; CHECK-NEXT: .cfi_offset %r15, -40 +; CHECK-NEXT: aghi %r15, -160 +; CHECK-NEXT: .cfi_def_cfa_offset 320 +; CHECK-NEXT: lgr %r5, %r3 +; CHECK-NEXT: lhi %r3, 0 +; CHECK-NEXT: lhi %r6, 0 +; CHECK-NEXT: brasl %r14, llvm.s390.translate@PLT +; CHECK-NEXT: lmg %r6, %r15, 208(%r15) +; CHECK-NEXT: br %r14 + call void @llvm.s390.translate(ptr %src, i32 0, i32 %len, ptr %tbl, i32 0) + ret void +} >From c36c7ef3ac69bc41aea3d152e1c741734886c575 Mon Sep 17 00:00:00 2001 From: patricklapgar <[email protected]> Date: Tue, 22 Sep 2026 00:05:55 -0700 Subject: [PATCH 6/6] cics tr support refactor --- clang/include/clang/Basic/BuiltinsSystemZ.td | 2 +- .../SystemZ/builtins-systemz-tr-invalid.c | 13 ++ .../CodeGen/SystemZ/builtins-systemz-tr.c | 74 +++++++--- llvm/include/llvm/IR/IntrinsicsSystemZ.td | 6 +- .../Target/SystemZ/SystemZISelLowering.cpp | 133 +++++++++++++----- llvm/lib/Target/SystemZ/SystemZISelLowering.h | 9 +- llvm/lib/Target/SystemZ/SystemZInstrInfo.td | 39 ++--- llvm/lib/Target/SystemZ/SystemZOperators.td | 14 +- .../CodeGen/SystemZ/translate-instruction.ll | 45 ------ .../test/CodeGen/SystemZ/translate-invalid.ll | 17 +++ llvm/test/CodeGen/SystemZ/translate.ll | 41 ++++++ 11 files changed, 253 insertions(+), 140 deletions(-) create mode 100644 clang/test/CodeGen/SystemZ/builtins-systemz-tr-invalid.c delete mode 100644 llvm/test/CodeGen/SystemZ/translate-instruction.ll create mode 100644 llvm/test/CodeGen/SystemZ/translate-invalid.ll create mode 100644 llvm/test/CodeGen/SystemZ/translate.ll diff --git a/clang/include/clang/Basic/BuiltinsSystemZ.td b/clang/include/clang/Basic/BuiltinsSystemZ.td index 978bf4ca39af0..c5b730c7c1b41 100644 --- a/clang/include/clang/Basic/BuiltinsSystemZ.td +++ b/clang/include/clang/Basic/BuiltinsSystemZ.td @@ -378,5 +378,5 @@ let Attributes = [NoThrow, Const], Features = "vector-enhancements-3" in { // String/General memory intrinsics let Attributes = [NoThrow] in { - def tr : SystemZTargetBuiltin<"void(void *, int, int, void *, int)">; + def tr : SystemZTargetBuiltin<"void(void *, unsigned long int, void const *)">; } \ No newline at end of file diff --git a/clang/test/CodeGen/SystemZ/builtins-systemz-tr-invalid.c b/clang/test/CodeGen/SystemZ/builtins-systemz-tr-invalid.c new file mode 100644 index 0000000000000..d650e6d2b74e0 --- /dev/null +++ b/clang/test/CodeGen/SystemZ/builtins-systemz-tr-invalid.c @@ -0,0 +1,13 @@ +// REQUIRES: systemz-registered-target +// RUN: not --crash %clang_cc1 -triple s390x-ibm-linux -S -O2 -o /dev/null %s 2>&1 | FileCheck %s + +// CHECK: error: TRANSLATE length must be a compile-time constant between 1 and 256 +// CHECK: error: TRANSLATE length must be a compile-time constant between 1 and 256 + +void tr_invalid_len_zero(char *src, const unsigned char *table) { + __builtin_s390_tr(src, 0, table); +} + +void tr_invalid_len_260(char *src, const unsigned char *table) { + __builtin_s390_tr(src, 260, table); +} diff --git a/clang/test/CodeGen/SystemZ/builtins-systemz-tr.c b/clang/test/CodeGen/SystemZ/builtins-systemz-tr.c index 18d78c6ca1391..25762f1d290df 100644 --- a/clang/test/CodeGen/SystemZ/builtins-systemz-tr.c +++ b/clang/test/CodeGen/SystemZ/builtins-systemz-tr.c @@ -1,37 +1,71 @@ // NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 6 -// RUN: %clang_cc1 -triple s390x-linux-gnu -target-cpu z13 -emit-llvm %s -o - | FileCheck %s +// REQUIRES: systemz-registered-target +// RUN: %clang_cc1 -triple s390x-ibm-linux -emit-llvm %s -o - | FileCheck %s -// CHECK-LABEL: define dso_local void @test_tr_static( -// CHECK-SAME: ptr noundef [[SRC:%.*]], ptr noundef [[TBL:%.*]]) #[[ATTR0:[0-9]+]] { +// CHECK-LABEL: define dso_local void @tr_len_five( +// CHECK-SAME: ptr noundef [[SRC:%.*]], ptr noundef [[TABLE:%.*]]) #[[ATTR0:[0-9]+]] { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: [[SRC_ADDR:%.*]] = alloca ptr, align 8 -// CHECK-NEXT: [[TBL_ADDR:%.*]] = alloca ptr, align 8 +// CHECK-NEXT: [[TABLE_ADDR:%.*]] = alloca ptr, align 8 // CHECK-NEXT: store ptr [[SRC]], ptr [[SRC_ADDR]], align 8 -// CHECK-NEXT: store ptr [[TBL]], ptr [[TBL_ADDR]], align 8 +// CHECK-NEXT: store ptr [[TABLE]], ptr [[TABLE_ADDR]], align 8 // CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[SRC_ADDR]], align 8 -// CHECK-NEXT: [[TMP1:%.*]] = load ptr, ptr [[TBL_ADDR]], align 8 -// CHECK-NEXT: call void @llvm.s390.translate(ptr [[TMP0]], i32 0, i32 16, ptr [[TMP1]], i32 0) +// CHECK-NEXT: [[TMP1:%.*]] = load ptr, ptr [[TABLE_ADDR]], align 8 +// CHECK-NEXT: call void @llvm.s390.translate(ptr [[TMP0]], i64 5, ptr [[TMP1]]) // CHECK-NEXT: ret void // -void test_tr_static(char *src, char *tbl) { - __builtin_s390_tr(src, 0, 16, tbl, 0); +void tr_len_five(char *src, const unsigned char *table) { + __builtin_s390_tr(src, 5, table); } -// CHECK-LABEL: define dso_local void @test_tr_variable( -// CHECK-SAME: ptr noundef [[SRC:%.*]], ptr noundef [[TBL:%.*]], i32 noundef signext [[LEN:%.*]]) #[[ATTR0]] { +// CHECK-LABEL: define dso_local void @tr_len_one( +// CHECK-SAME: ptr noundef [[SRC:%.*]], ptr noundef [[TABLE:%.*]]) #[[ATTR0]] { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: [[SRC_ADDR:%.*]] = alloca ptr, align 8 -// CHECK-NEXT: [[TBL_ADDR:%.*]] = alloca ptr, align 8 -// CHECK-NEXT: [[LEN_ADDR:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[TABLE_ADDR:%.*]] = alloca ptr, align 8 // CHECK-NEXT: store ptr [[SRC]], ptr [[SRC_ADDR]], align 8 -// CHECK-NEXT: store ptr [[TBL]], ptr [[TBL_ADDR]], align 8 -// CHECK-NEXT: store i32 [[LEN]], ptr [[LEN_ADDR]], align 4 +// CHECK-NEXT: store ptr [[TABLE]], ptr [[TABLE_ADDR]], align 8 // CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[SRC_ADDR]], align 8 -// CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[LEN_ADDR]], align 4 -// CHECK-NEXT: [[TMP2:%.*]] = load ptr, ptr [[TBL_ADDR]], align 8 -// CHECK-NEXT: call void @llvm.s390.translate(ptr [[TMP0]], i32 0, i32 [[TMP1]], ptr [[TMP2]], i32 0) +// CHECK-NEXT: [[TMP1:%.*]] = load ptr, ptr [[TABLE_ADDR]], align 8 +// CHECK-NEXT: call void @llvm.s390.translate(ptr [[TMP0]], i64 1, ptr [[TMP1]]) // CHECK-NEXT: ret void // -void test_tr_variable(char *src, char *tbl, int len) { - __builtin_s390_tr(src, 0, len, tbl, 0); +void tr_len_one(char *src, const unsigned char *table) { + __builtin_s390_tr(src, 1, table); +} + +// CHECK-LABEL: define dso_local void @tr_len_256( +// CHECK-SAME: ptr noundef [[SRC:%.*]], ptr noundef [[TABLE:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[SRC_ADDR:%.*]] = alloca ptr, align 8 +// CHECK-NEXT: [[TABLE_ADDR:%.*]] = alloca ptr, align 8 +// CHECK-NEXT: store ptr [[SRC]], ptr [[SRC_ADDR]], align 8 +// CHECK-NEXT: store ptr [[TABLE]], ptr [[TABLE_ADDR]], align 8 +// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[SRC_ADDR]], align 8 +// CHECK-NEXT: [[TMP1:%.*]] = load ptr, ptr [[TABLE_ADDR]], align 8 +// CHECK-NEXT: call void @llvm.s390.translate(ptr [[TMP0]], i64 256, ptr [[TMP1]]) +// CHECK-NEXT: ret void +// +void tr_len_256(char *src, const unsigned char *table) { + __builtin_s390_tr(src, 256, table); +} + +// CHECK-LABEL: define dso_local void @tr_len_variable( +// CHECK-SAME: ptr noundef [[SRC:%.*]], i64 noundef [[LENGTH:%.*]], ptr noundef [[TABLE:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[SRC_ADDR:%.*]] = alloca ptr, align 8 +// CHECK-NEXT: [[LENGTH_ADDR:%.*]] = alloca i64, align 8 +// CHECK-NEXT: [[TABLE_ADDR:%.*]] = alloca ptr, align 8 +// CHECK-NEXT: store ptr [[SRC]], ptr [[SRC_ADDR]], align 8 +// CHECK-NEXT: store i64 [[LENGTH]], ptr [[LENGTH_ADDR]], align 8 +// CHECK-NEXT: store ptr [[TABLE]], ptr [[TABLE_ADDR]], align 8 +// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[SRC_ADDR]], align 8 +// CHECK-NEXT: [[TMP1:%.*]] = load i64, ptr [[LENGTH_ADDR]], align 8 +// CHECK-NEXT: [[TMP2:%.*]] = load ptr, ptr [[TABLE_ADDR]], align 8 +// CHECK-NEXT: call void @llvm.s390.translate(ptr [[TMP0]], i64 [[TMP1]], ptr [[TMP2]]) +// CHECK-NEXT: ret void +// +void tr_len_variable(char *src, long length, + const unsigned char *table) { + __builtin_s390_tr(src, length, table); } diff --git a/llvm/include/llvm/IR/IntrinsicsSystemZ.td b/llvm/include/llvm/IR/IntrinsicsSystemZ.td index 9d87202439053..d4bcbf29ebb7a 100644 --- a/llvm/include/llvm/IR/IntrinsicsSystemZ.td +++ b/llvm/include/llvm/IR/IntrinsicsSystemZ.td @@ -506,9 +506,9 @@ let TargetPrefix = "s390" in { let TargetPrefix = "s390" in { def int_s390_translate : Intrinsic<[], - [llvm_ptr_ty, llvm_i32_ty, llvm_i32_ty, - llvm_ptr_ty, llvm_i32_ty], + [llvm_ptr_ty, llvm_i64_ty, llvm_ptr_ty], [IntrArgMemOnly, - NoCapture<ArgIndex<0>>, NoCapture<ArgIndex<3>>]>, + NoCapture<ArgIndex<0>>, + NoCapture<ArgIndex<2>>]>, ClangBuiltin<"__builtin_s390_tr">; } \ No newline at end of file diff --git a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp index 5e8884fa52cfc..9868bbd67126d 100644 --- a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp +++ b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp @@ -807,6 +807,7 @@ SystemZTargetLowering::SystemZTargetLowering(const TargetMachine &TM, // Handle intrinsics. setOperationAction(ISD::INTRINSIC_W_CHAIN, MVT::Other, Custom); + setOperationAction(ISD::INTRINSIC_VOID, MVT::Other, Custom); setOperationAction(ISD::INTRINSIC_WO_CHAIN, MVT::Other, Custom); // We're not using SJLJ for exception handling, but they're implemented @@ -4207,6 +4208,36 @@ SDValue SystemZTargetLowering::lowerTLSGetOffset(GlobalAddressSDNode *Node, return DAG.getCopyFromReg(Chain, DL, SystemZ::R2D, PtrVT, Glue); } +SDValue SystemZTargetLowering::lowerTR(SDValue Op, + SelectionDAG &DAG) const { + SDLoc DL(Op); + + SDValue Chain = Op.getOperand(0); + SDValue Src = Op.getOperand(2); + SDValue Len = Op.getOperand(3); + SDValue Tbl = Op.getOperand(4); + + // For compile-time constant lengths, validate range [1, 256]. + // Variable lengths are handled (or rejected) by the instruction at runtime. + if(auto *C = dyn_cast<ConstantSDNode>(Len)) { + uint64_t LenVal = C->getZExtValue(); + if(LenVal < 1 || LenVal > 256) { + DAG.getContext()->emitError( + "TRANSLATE length must be a compile-time constant between 1 and 256"); + return DAG.getUNDEF(MVT::Other); + } + } + + // Adjust the provided length to encode length-1. Both TR and EXRL + // instructions must carry the adjusted value. + SDValue AdjLen = DAG.getNode(ISD::ADD, DL, MVT::i64, + DAG.getZExtOrTrunc(Len, DL, MVT::i64), + DAG.getSignedConstant(-1, DL, MVT::i64)); + + SDValue Ops[] = { Chain, Src, AdjLen, Tbl }; + return DAG.getNode(SystemZISD::TR, DL, MVT::Other, Ops); +} + SDValue SystemZTargetLowering::lowerThreadPointer(const SDLoc &DL, SelectionDAG &DAG) const { SDValue Chain = DAG.getEntryNode(); @@ -5457,6 +5488,20 @@ SystemZTargetLowering::lowerINTRINSIC_W_CHAIN(SDValue Op, return SDValue(); } +SDValue +SystemZTargetLowering::lowerINTRINSIC_VOID(SDValue Op, + SelectionDAG &DAG) const { + unsigned Id = Op.getConstantOperandVal(1); + switch(Id) { + case Intrinsic::s390_translate: + return lowerTR(Op, DAG); + default: + break; + } + + return SDValue(); +} + SDValue SystemZTargetLowering::lowerINTRINSIC_WO_CHAIN(SDValue Op, SelectionDAG &DAG) const { @@ -7299,6 +7344,8 @@ SDValue SystemZTargetLowering::LowerOperation(SDValue Op, return lowerPREFETCH(Op, DAG); case ISD::INTRINSIC_W_CHAIN: return lowerINTRINSIC_W_CHAIN(Op, DAG); + case ISD::INTRINSIC_VOID: + return lowerINTRINSIC_VOID(Op, DAG); case ISD::INTRINSIC_WO_CHAIN: return lowerINTRINSIC_WO_CHAIN(Op, DAG); case ISD::BUILD_VECTOR: @@ -10525,39 +10572,59 @@ MachineBasicBlock *SystemZTargetLowering::emitExt128(MachineInstr &MI, } MachineBasicBlock * -SystemZTargetLowering::emitTRWrapper(MachineInstr &MI, - MachineBasicBlock *MBB, - unsigned Opcode) const { - MachineFunction &MF = *MBB->getParent(); - MachineRegisterInfo &MRI = MF.getRegInfo(); - const SystemZInstrInfo *TII = - static_cast<const SystemZInstrInfo *>(Subtarget.getInstrInfo()); +SystemZTargetLowering::emitTRImm(MachineInstr &MI, + MachineBasicBlock *MBB) const { + const SystemZInstrInfo *TII = Subtarget.getInstrInfo(); DebugLoc DL = MI.getDebugLoc(); - Register SrcReg = MI.getOperand(0).getReg(); - int64_t D1Imm = MI.getOperand(1).getImm(); - Register LenReg = MI.getOperand(2).getReg(); - Register TblReg = MI.getOperand(3).getReg(); - int64_t D2Imm = MI.getOperand(4).getImm(); - - MRI.constrainRegClass(SrcReg, &SystemZ::ADDR64BitRegClass); - MRI.constrainRegClass(TblReg, &SystemZ::ADDR64BitRegClass); - - Register Len32Reg = MRI.createVirtualRegister(&SystemZ::GR32BitRegClass); - BuildMI(*MBB, MI, DL, TII->get(SystemZ::AHI), Len32Reg) - .addReg(LenReg) - .addImm(-1); - - // Must constrain 32-bit length register to 64-bit for EXRL execution - Register Len64Reg = MRI.createVirtualRegister(&SystemZ::ADDR64BitRegClass); - BuildMI(*MBB, MI, DL, TII->get(SystemZ::LLGFR), Len64Reg) - .addReg(Len32Reg); - + MachineOperand SrcBase = earlyUseOperand(MI.getOperand(0)); + uint64_t SrcDisp = MI.getOperand(1).getImm(); + uint64_t SrcLen = MI.getOperand(2).getImm(); + MachineOperand TblBase = earlyUseOperand(MI.getOperand(3)); + uint64_t TblDisp = MI.getOperand(4).getImm(); + + // TR instr expects the following format: + // - 1st op (source): (base, disp. length) + // - 2nd op (translation table): (base, disp.) + // Note: The provided length has alread been adjusted, so + // passing the length op's immediate let TR's encoder + // to leave it as-is and not subtract 1 a second time. + BuildMI(*MBB, MI, DL, TII->get(SystemZ::TR)) + .add(SrcBase).addImm(SrcDisp).addImm(SrcLen) // BDL1 + .add(TblBase).addImm(TblDisp); // BDL2 + + MI.eraseFromParent(); + return MBB; +} + +MachineBasicBlock * +SystemZTargetLowering::emitTRReg(MachineInstr &MI, + MachineBasicBlock *MBB) const { + const SystemZInstrInfo *TII = Subtarget.getInstrInfo(); + DebugLoc DL = MI.getDebugLoc(); + + MachineOperand SrcBase = earlyUseOperand(MI.getOperand(0)); + uint64_t SrcDisp = MI.getOperand(1).getImm(); + Register SrcLen = MI.getOperand(2).getReg(); + MachineOperand TblBase = earlyUseOperand(MI.getOperand(3)); + uint64_t TblDisp = MI.getOperand(4).getImm(); + + // To handle variable-length values, the TR pseudo must be + // lowered into EXRL_Pseudo. This way, EXRL will execute the TR + // instruction along w/ any addtl. instructions needed to compute + // the value of the provided length. Both address bases must be + // placed into dedicate virtual regs before sendoff to EXRL_Pseudo. + Register SrcReg = forceReg(MI, SrcBase, TII); + Register TblReg = forceReg(MI, TblBase, TII); + + // Unlike the official TR instruction, EXRL_Pseudo already expects + // an adjusted length value to be provided, which at this point has + // already been done via lowerTR(), so no further adjustment needed. BuildMI(*MBB, MI, DL, TII->get(SystemZ::EXRL_Pseudo)) - .addImm(Opcode) - .addReg(Len64Reg) - .addReg(SrcReg).addImm(D1Imm) - .addReg(TblReg).addImm(D2Imm); + .addImm(SystemZ::TR) + .addReg(SrcLen) + .addReg(SrcReg).addImm(SrcDisp) // BDL1 + .addReg(TblReg).addImm(TblDisp); // BD2 MI.eraseFromParent(); return MBB; @@ -11370,8 +11437,10 @@ MachineBasicBlock *SystemZTargetLowering::EmitInstrWithCustomInserter( case SystemZ::CMP_STACKGUARD_DAG: return emitStackGuardPseudo(MI, MBB, SystemZ::CMP_STACKGUARD); - case SystemZ::TR_Pseudo: - return emitTRWrapper(MI, MBB, SystemZ::TR); + case SystemZ::TRImm: + return emitTRImm(MI, MBB); + case SystemZ::TRReg: + return emitTRReg(MI, MBB); default: llvm_unreachable("Unexpected instr type to insert"); diff --git a/llvm/lib/Target/SystemZ/SystemZISelLowering.h b/llvm/lib/Target/SystemZ/SystemZISelLowering.h index b7b27532f7e4d..74678814dc198 100644 --- a/llvm/lib/Target/SystemZ/SystemZISelLowering.h +++ b/llvm/lib/Target/SystemZ/SystemZISelLowering.h @@ -382,6 +382,7 @@ class SystemZTargetLowering : public TargetLowering { SDValue lowerSTACKRESTORE(SDValue Op, SelectionDAG &DAG) const; SDValue lowerPREFETCH(SDValue Op, SelectionDAG &DAG) const; SDValue lowerINTRINSIC_W_CHAIN(SDValue Op, SelectionDAG &DAG) const; + SDValue lowerINTRINSIC_VOID(SDValue Op, SelectionDAG &DAG) const; SDValue lowerINTRINSIC_WO_CHAIN(SDValue Op, SelectionDAG &DAG) const; bool isVectorElementLoad(SDValue Op) const; SDValue buildVector(SelectionDAG &DAG, const SDLoc &DL, EVT VT, @@ -494,9 +495,11 @@ class SystemZTargetLowering : public TargetLowering { getTargetMMOFlags(const Instruction &I) const override; const TargetRegisterClass *getRepRegClassFor(MVT VT) const override; - MachineBasicBlock *emitTRWrapper(MachineInstr &MI, - MachineBasicBlock *MBB, - unsigned Opcode) const; + SDValue lowerTR(SDValue Op, SelectionDAG &DAG) const; + MachineBasicBlock *emitTRImm(MachineInstr &MI, + MachineBasicBlock *MBB) const; + MachineBasicBlock *emitTRReg(MachineInstr &MI, + MachineBasicBlock *MBB) const; private: bool isInternal(const Function *Fn) const; diff --git a/llvm/lib/Target/SystemZ/SystemZInstrInfo.td b/llvm/lib/Target/SystemZ/SystemZInstrInfo.td index 2784a58d00952..3965d457a3bad 100644 --- a/llvm/lib/Target/SystemZ/SystemZInstrInfo.td +++ b/llvm/lib/Target/SystemZ/SystemZInstrInfo.td @@ -2272,34 +2272,17 @@ let hasSideEffects = 1 in { } // Translate -let hasSideEffects = 1, usesCustomInserter = 1, - hasNoSchedulingInfo = 1, mayLoad = 1, - mayStore = 1, Defs = [CC] in { - def TR_Pseudo : Pseudo<(outs), (ins GR64:$src, i32imm:$D1, GR32:$len, - GR64:$tbl, i32imm:$D2), []>; - // [(z_tr GR64:$src, i32imm:$D1, GR32:$len, - // GR64:$tbl, i32imm:$D2)]>; -} - -// Transform constant length N (1..256) into N - 1 for SS-format -def tr_len : SDNodeXForm<imm, [{ - return CurDAG->getTargetConstant(N->getZExtValue() - 1, SDLoc(N), MVT::i32); -}]>; - -def tr_len_leaf : ImmLeaf<i32, - [{ return N->getZExtValue() >= 1 && N->getZExtValue() <= 256; }], - tr_len ->; - -// Match TR invocation w/ a static constant provided as the length -def : Pat<(int_s390_translate ADDR64:$src, i32:$D1, tr_len_leaf:$len, - ADDR64:$tbl, i32:$D2), - (TR (bdladdr12onlylen8 ADDR64:$src, i32:$D1, tr_len_leaf:$len), - (bdaddr12only ADDR64:$tbl, i32:$D2))>; - -// Match TR invocation w/ a variable provided as the length -def : Pat<(int_s390_translate ADDR64:$src, i32:$D1, GR32:$len, GR64:$tbl, i32:$D2), - (TR_Pseudo ADDR64:$src, i32:$D1, GR32:$len, ADDR64:$tbl, i32:$D2)>; +let usesCustomInserter = 1, hasNoSchedulingInfo = 1, + mayLoad = 1, mayStore = 1 in { + + // Match TR invocation w/ static constant length + def TRImm : Pseudo<(outs), (ins bdaddr12only:$bd1, imm64:$len, bdaddr12only:$bd2), + [(z_tr bdaddr12only:$bd1, imm64:$len, bdaddr12only:$bd2)]>; + + // Match TR invocation w/ variable length + def TRReg : Pseudo<(outs), (ins bdaddr12only:$bd1, ADDR64:$len, bdaddr12only:$bd2), + [(z_tr bdaddr12only:$bd1, ADDR64:$len, bdaddr12only:$bd2)]>; +} //===----------------------------------------------------------------------===// // .insn directive instructions diff --git a/llvm/lib/Target/SystemZ/SystemZOperators.td b/llvm/lib/Target/SystemZ/SystemZOperators.td index b0a5327d92c04..cca85649a659d 100644 --- a/llvm/lib/Target/SystemZ/SystemZOperators.td +++ b/llvm/lib/Target/SystemZ/SystemZOperators.td @@ -257,12 +257,10 @@ def SDT_ZSetJmp : SDTypeProfile<1, 1, SDTCisPtrTy<1>]>; def SDT_ZLongJmp : SDTypeProfile<0, 1, [SDTCisPtrTy<0>]>; -// def SDT_ZTranslate : SDTypeProfile<0, 5, -// [SDTCisPtrTy<0>, -// SDTCisInt<1>, -// SDTCisInt<2>, -// SDTCisPtrTy<3>, -// SDTCisInt<4>]>; +def SDT_ZTranslate : SDTypeProfile<0, 3, + [SDTCisPtrTy<0>, + SDTCisVT<1, i64>, + SDTCisPtrTy<2>]>; //===----------------------------------------------------------------------===// // Node definitions @@ -427,8 +425,8 @@ def z_stckf : SDNode<"SystemZISD::STCKF", SDT_ZStoreInherent, [SDNPHasChain, SDNPMayStore, SDNPMemOperand]>; // Translate string data from one code to another code -// def z_tr : SDNode<"SystemZISD::TR", SDT_ZTranslate, -// [SDNPHasChain, SDNPMayLoad, SDNPMayStore]>; +def z_tr : SDNode<"SystemZISD::TR", SDT_ZTranslate, + [SDNPHasChain, SDNPMayLoad, SDNPMayStore]>; // Test Data Class. // diff --git a/llvm/test/CodeGen/SystemZ/translate-instruction.ll b/llvm/test/CodeGen/SystemZ/translate-instruction.ll deleted file mode 100644 index 8458875838e91..0000000000000 --- a/llvm/test/CodeGen/SystemZ/translate-instruction.ll +++ /dev/null @@ -1,45 +0,0 @@ -; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6 -; RUN: llc < %s -mtriple=s390x-linux-gnu -mcpu=z13 -verify-machineinstrs | FileCheck %s - -declare void @llvm.s390.translate(ptr, i32, i32, ptr, i32) - -;Test 1: Static constant length -> Direct TR instruction -define void @test_tr_static(ptr %src, ptr %tbl) { -; CHECK-LABEL: test_tr_static: -; CHECK: # %bb.0: -; CHECK-NEXT: stmg %r6, %r15, 48(%r15) -; CHECK-NEXT: .cfi_offset %r6, -112 -; CHECK-NEXT: .cfi_offset %r14, -48 -; CHECK-NEXT: .cfi_offset %r15, -40 -; CHECK-NEXT: aghi %r15, -160 -; CHECK-NEXT: .cfi_def_cfa_offset 320 -; CHECK-NEXT: lgr %r5, %r3 -; CHECK-NEXT: lhi %r3, 0 -; CHECK-NEXT: lhi %r4, 16 -; CHECK-NEXT: lhi %r6, 0 -; CHECK-NEXT: brasl %r14, llvm.s390.translate@PLT -; CHECK-NEXT: lmg %r6, %r15, 208(%r15) -; CHECK-NEXT: br %r14 - call void @llvm.s390.translate(ptr %src, i32 0, i32 16, ptr %tbl, i32 0) - ret void -} - -; Test 2: Variable length -> AHI (decrement by 1) + EXRL execution -define void @test_tr_variable(ptr %src, ptr %tbl, i32 %len) { -; CHECK-LABEL: test_tr_variable: -; CHECK: # %bb.0: -; CHECK-NEXT: stmg %r6, %r15, 48(%r15) -; CHECK-NEXT: .cfi_offset %r6, -112 -; CHECK-NEXT: .cfi_offset %r14, -48 -; CHECK-NEXT: .cfi_offset %r15, -40 -; CHECK-NEXT: aghi %r15, -160 -; CHECK-NEXT: .cfi_def_cfa_offset 320 -; CHECK-NEXT: lgr %r5, %r3 -; CHECK-NEXT: lhi %r3, 0 -; CHECK-NEXT: lhi %r6, 0 -; CHECK-NEXT: brasl %r14, llvm.s390.translate@PLT -; CHECK-NEXT: lmg %r6, %r15, 208(%r15) -; CHECK-NEXT: br %r14 - call void @llvm.s390.translate(ptr %src, i32 0, i32 %len, ptr %tbl, i32 0) - ret void -} diff --git a/llvm/test/CodeGen/SystemZ/translate-invalid.ll b/llvm/test/CodeGen/SystemZ/translate-invalid.ll new file mode 100644 index 0000000000000..b7b54841bc080 --- /dev/null +++ b/llvm/test/CodeGen/SystemZ/translate-invalid.ll @@ -0,0 +1,17 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6 +; RUN: not --crash llc < %s -mtriple=s390x-linux-gnu 2>&1 | FileCheck %s + +; CHECK: error: TRANSLATE length must be a compile-time constant between 1 and 256 +; CHECK: error: TRANSLATE length must be a compile-time constant between 1 and 256 + +declare void @llvm.s390.translate(ptr, i64, ptr) + +define void @tr_invalid_len_zero(ptr %src, ptr %table) { + call void @llvm.s390.translate(ptr %src, i64 0, ptr %table) + ret void +} + +define void @tr_invalid_len_260(ptr %src, ptr %table) { + call void @llvm.s390.translate(ptr %src, i64 260, ptr %table) + ret void +} diff --git a/llvm/test/CodeGen/SystemZ/translate.ll b/llvm/test/CodeGen/SystemZ/translate.ll new file mode 100644 index 0000000000000..6fb2b07e1627f --- /dev/null +++ b/llvm/test/CodeGen/SystemZ/translate.ll @@ -0,0 +1,41 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6 +; RUN: llc < %s -mtriple=s390x-linux-gnu -verify-machineinstrs | FileCheck %s + +declare void @llvm.s390.translate(ptr, i64, ptr) + +define void @tr_len_five(ptr %src, ptr %table) { +; CHECK-LABEL: tr_len_five: +; CHECK: # %bb.0: +; CHECK-NEXT: tr 0(4,%r2), 0(%r3) +; CHECK-NEXT: br %r14 + call void @llvm.s390.translate(ptr %src, i64 5, ptr %table) + ret void +} + +define void @tr_len_one(ptr %src, ptr %table) { +; CHECK-LABEL: tr_len_one: +; CHECK: # %bb.0: +; CHECK-NEXT: tr 0(0,%r2), 0(%r3) +; CHECK-NEXT: br %r14 + call void @llvm.s390.translate(ptr %src, i64 1, ptr %table) + ret void +} + +define void @tr_len_256(ptr %src, ptr %table) { +; CHECK-LABEL: tr_len_256: +; CHECK: # %bb.0: +; CHECK-NEXT: tr 0(255,%r2), 0(%r3) +; CHECK-NEXT: br %r14 + call void @llvm.s390.translate(ptr %src, i64 256, ptr %table) + ret void +} + +define void @tr_len_variable(ptr %src, i64 %length, ptr %table) { +; CHECK-LABEL: tr_len_variable: +; CHECK: # %bb.0: +; CHECK-NEXT: aghi %r3, -1 +; CHECK-NEXT: exrl %r3, .Ltmp0 +; CHECK-NEXT: br %r14 + call void @llvm.s390.translate(ptr %src, i64 %length, ptr %table) + ret void +} _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
