Index: llvm/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp =================================================================== --- llvm/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp +++ llvm/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp @@ -1621,6 +1621,50 @@ } break; } + + // Since Access registers can only be copied using low GR32 regs while + // GRX32 is the default register class, these copies must be handled here. + case ISD::CopyToReg: { + unsigned DestReg = cast(Node->getOperand(1))->getReg(); + if (SystemZ::AR32BitRegClass.contains(DestReg)) { + // Insert a COPY_TO_REGCLASS to get the copied value into a GR32 reg. + SDLoc DL(Node); + SDValue Chain = Node->getOperand(0); + SDValue SrcValue = Node->getOperand(2); + SDValue CopyToRegClass = + SDValue(CurDAG->getMachineNode( + SystemZ::COPY_TO_REGCLASS, DL, MVT::i32, SrcValue, + CurDAG->getTargetConstant(SystemZ::GR32BitRegClassID, DL, + MVT::i32)), + 0); + SDValue Res = + CurDAG->getCopyToReg(Chain, DL, DestReg, CopyToRegClass, SDValue()); + ReplaceNode(Node, Res.getNode()); + return; + } + break; + } + + case ISD::CopyFromReg: { + unsigned SrcReg = cast(Node->getOperand(1))->getReg(); + if (SystemZ::AR32BitRegClass.contains(SrcReg)) { + // Insert a temporary pseudo opcode with a GR32 use operand to + // constrain the created virtreg to GR32. + SDLoc DL(Node); + SDValue Chain = Node->getOperand(0); + SDValue InGlue = + Node->getNumOperands() == 3 ? Node->getOperand(2) : SDValue(); + SDValue CopyFromReg = + CurDAG->getCopyFromReg(Chain, DL, SrcReg, MVT::i32, InGlue); + SDNode *Res = CurDAG->getMachineNode( + SystemZ::CopyGR32, DL, MVT::i32, MVT::Other, MVT::Glue, + CopyFromReg); + CurDAG->ReplaceAllUsesWith(Node, Res); + return; + } + break; + } + } SelectCode(Node); Index: llvm/lib/Target/SystemZ/SystemZISelLowering.cpp =================================================================== --- llvm/lib/Target/SystemZ/SystemZISelLowering.cpp +++ llvm/lib/Target/SystemZ/SystemZISelLowering.cpp @@ -8053,6 +8053,10 @@ case TargetOpcode::PATCHPOINT: return emitPatchPoint(MI, MBB); + case SystemZ::CopyGR32: + MI.setDesc(Subtarget.getInstrInfo()->get(SystemZ::COPY)); + return MBB; + default: llvm_unreachable("Unexpected instr type to insert"); } Index: llvm/lib/Target/SystemZ/SystemZInstrInfo.td =================================================================== --- llvm/lib/Target/SystemZ/SystemZInstrInfo.td +++ llvm/lib/Target/SystemZ/SystemZInstrInfo.td @@ -1974,6 +1974,13 @@ // Access registers //===----------------------------------------------------------------------===// +// Make sure Access Registers are handled with GR32 via custom +// insertion. When a CopyFromReg from an access register gets selected, a +// CopyGR32 is inserted as its user which is then changed to a COPY after the +// virtreg has been constrained to GR32 during instruction selection. +let usesCustomInserter = 1, hasNoSchedulingInfo = 1 in + def CopyGR32 : Pseudo<(outs GR32:$Dst), (ins GR32:$SrcAR), []>; + // Read a 32-bit access register into a GR32. As with all GR32 operations, // the upper 32 bits of the enclosing GR64 remain unchanged, which is useful // when a 64-bit address is stored in a pair of access registers. Index: llvm/test/CodeGen/SystemZ/tls-08.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/SystemZ/tls-08.ll @@ -0,0 +1,22 @@ +; RUN: llc < %s -mcpu=z196 -mtriple=s390x-linux-gnu -O0 -stop-after=finalize-isel \ +; RUN: 2>&1 | FileCheck %s +; REQUIRES: asserts +; +; Test that copies to/from access registers are emitted from isel with GR32 regs. + +@x = dso_local thread_local global i32 0, align 4 +define weak_odr hidden i32* @fun0() { +; CHECK: name: fun0 +; CHECK: %{{[0-9]+}}:gr32bit = COPY $a0 +; CHECK: %{{[0-9]+}}:gr32bit = COPY $a1 + ret i32* @x +} + +define i32 @fun1() { +; CHECK: name: fun1 +; CHECK: %1:gr32bit = COPY %0 +; CHECK: $a1 = COPY %1 +; CHECK: %2:gr32bit = COPY $a0 + %val = call i32 asm "blah", "={a0}, {a1}" (i32 0) + ret i32 %val +} Index: llvm/test/CodeGen/SystemZ/tls-09.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/SystemZ/tls-09.ll @@ -0,0 +1,37 @@ +; RUN: llc < %s -mcpu=z196 -mtriple=s390x-linux-gnu -O0 +; +; Test that a0 and a1 are copied successfully into GR32 registers. + +@x = dso_local thread_local global i32 0, align 4 +define i32 @fun0(i32 signext, i32 signext, i32 signext, i32 signext, i32 signext, i32 signext, i32 signext) { + %8 = alloca i32, align 4 + %9 = alloca i32, align 4 + %10 = alloca i32, align 4 + %11 = alloca i32, align 4 + %12 = alloca i32, align 4 + %13 = alloca i32, align 4 + %14 = alloca i32, align 4 + %15 = load i32, i32* @x, align 4 + store i32 %0, i32* %8, align 4 + store i32 %1, i32* %9, align 4 + store i32 %2, i32* %10, align 4 + store i32 %3, i32* %11, align 4 + store i32 %4, i32* %12, align 4 + store i32 %5, i32* %13, align 4 + store i32 %6, i32* %14, align 4 + %16 = load i32, i32* %8, align 4 + %17 = add nsw i32 %15, %16 + %18 = load i32, i32* %9, align 4 + %19 = add nsw i32 %17, %18 + %20 = load i32, i32* %10, align 4 + %21 = add nsw i32 %19, %20 + %22 = load i32, i32* %11, align 4 + %23 = add nsw i32 %21, %22 + %24 = load i32, i32* %12, align 4 + %25 = add nsw i32 %23, %24 + %26 = load i32, i32* %13, align 4 + %27 = add nsw i32 %25, %26 + %28 = load i32, i32* %14, align 4 + %29 = add nsw i32 %27, %28 + ret i32 %29 +}