diff --git a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp --- a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp +++ b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp @@ -1076,6 +1076,7 @@ case PPC::GETtlsADDR: // Transform: %x3 = GETtlsADDR %x3, @sym // Into: BL8_NOP_TLS __tls_get_addr(sym at tlsgd) + case PPC::GETtlsADDRPCREL: case PPC::GETtlsADDR32: { // Transform: %r3 = GETtlsADDR32 %r3, @sym // Into: BL_TLS __tls_get_addr(sym at tlsgd)@PLT @@ -1121,6 +1122,7 @@ case PPC::GETtlsldADDR: // Transform: %x3 = GETtlsldADDR %x3, @sym // Into: BL8_NOP_TLS __tls_get_addr(sym at tlsld) + case PPC::GETtlsldADDRPCREL: case PPC::GETtlsldADDR32: { // Transform: %r3 = GETtlsldADDR32 %r3, @sym // Into: BL_TLS __tls_get_addr(sym at tlsld)@PLT diff --git a/llvm/lib/Target/PowerPC/PPCInstr64Bit.td b/llvm/lib/Target/PowerPC/PPCInstr64Bit.td --- a/llvm/lib/Target/PowerPC/PPCInstr64Bit.td +++ b/llvm/lib/Target/PowerPC/PPCInstr64Bit.td @@ -1265,17 +1265,36 @@ [(set i64:$rD, (PPCaddiTlsgdL i64:$reg, tglobaltlsaddr:$disp))]>, isPPC64; -// LR8 is a true define, while the rest of the Defs are clobbers. X3 is + +class GETtlsADDRPseudo : PPCEmitTimePseudo<(outs g8rc:$rD), (ins g8rc:$reg, tlsgd:$sym), + asmstr, + [(set i64:$rD, + (PPCgetTlsAddr i64:$reg, tglobaltlsaddr:$sym))]>, + isPPC64; +class GETtlsldADDRPseudo : PPCEmitTimePseudo<(outs g8rc:$rD), (ins g8rc:$reg, tlsgd:$sym), + asmstr, + [(set i64:$rD, + (PPCgetTlsldAddr i64:$reg, tglobaltlsaddr:$sym))]>, + isPPC64; + +let hasExtraSrcRegAllocReq = 1, hasExtraDefRegAllocReq = 1 in { +// LR8 is a true define, while the rest of the Defs are clobbers. X3 is // explicitly defined when this op is created, so not mentioned here. // This is lowered to BL8_NOP_TLS by the assembly printer, so the size must be // correct because the branch select pass is relying on it. -let hasExtraSrcRegAllocReq = 1, hasExtraDefRegAllocReq = 1, Size = 8, - Defs = [X0,X4,X5,X6,X7,X8,X9,X10,X11,X12,LR8,CTR8,CR0,CR1,CR5,CR6,CR7] in -def GETtlsADDR : PPCEmitTimePseudo<(outs g8rc:$rD), (ins g8rc:$reg, tlsgd:$sym), - "#GETtlsADDR", - [(set i64:$rD, - (PPCgetTlsAddr i64:$reg, tglobaltlsaddr:$sym))]>, - isPPC64; +let Defs = [X0,X4,X5,X6,X7,X8,X9,X10,X11,X12,LR8,CTR8,CR0,CR1,CR5,CR6,CR7], Size = 8 in +def GETtlsADDR : GETtlsADDRPseudo <"#GETtlsADDR">; +let Defs = [X0,X2,X4,X5,X6,X7,X8,X9,X10,X11,X12,LR8,CTR8,CR0,CR1,CR5,CR6,CR7], Size = 8 in +def GETtlsADDRPCREL : GETtlsADDRPseudo <"#GETtlsADDRPCREL">; + +// LR8 is a true define, while the rest of the Defs are clobbers. X3 is +// explicitly defined when this op is created, so not mentioned here. +let Defs = [X0,X4,X5,X6,X7,X8,X9,X10,X11,X12,LR8,CTR8,CR0,CR1,CR5,CR6,CR7] in +def GETtlsldADDR : GETtlsldADDRPseudo <"#GETtlsldADDR">; +let Defs = [X0,X2,X4,X5,X6,X7,X8,X9,X10,X11,X12,LR8,CTR8,CR0,CR1,CR5,CR6,CR7] in +def GETtlsldADDRPCREL : GETtlsldADDRPseudo <"#GETtlsldADDRPCREL">; +} + // Combined op for ADDItlsgdL and GETtlsADDR, late expanded. X3 and LR8 // are true defines while the rest of the Defs are clobbers. let hasExtraSrcRegAllocReq = 1, hasExtraDefRegAllocReq = 1, @@ -1299,15 +1318,6 @@ [(set i64:$rD, (PPCaddiTlsldL i64:$reg, tglobaltlsaddr:$disp))]>, isPPC64; -// LR8 is a true define, while the rest of the Defs are clobbers. X3 is -// explicitly defined when this op is created, so not mentioned here. -let hasExtraSrcRegAllocReq = 1, hasExtraDefRegAllocReq = 1, - Defs = [X0,X4,X5,X6,X7,X8,X9,X10,X11,X12,LR8,CTR8,CR0,CR1,CR5,CR6,CR7] in -def GETtlsldADDR : PPCEmitTimePseudo<(outs g8rc:$rD), (ins g8rc:$reg, tlsgd:$sym), - "#GETtlsldADDR", - [(set i64:$rD, - (PPCgetTlsldAddr i64:$reg, tglobaltlsaddr:$sym))]>, - isPPC64; // Combined op for ADDItlsldL and GETtlsADDR, late expanded. X3 and LR8 // are true defines, while the rest of the Defs are clobbers. let hasExtraSrcRegAllocReq = 1, hasExtraDefRegAllocReq = 1, diff --git a/llvm/lib/Target/PowerPC/PPCTLSDynamicCall.cpp b/llvm/lib/Target/PowerPC/PPCTLSDynamicCall.cpp --- a/llvm/lib/Target/PowerPC/PPCTLSDynamicCall.cpp +++ b/llvm/lib/Target/PowerPC/PPCTLSDynamicCall.cpp @@ -111,8 +111,8 @@ Opc1 = PPC::PADDI8pc; Opc2 = MI.getOperand(2).getTargetFlags() == PPCII::MO_GOT_TLSGD_PCREL_FLAG - ? PPC::GETtlsADDR - : PPC::GETtlsldADDR; + ? PPC::GETtlsADDRPCREL + : PPC::GETtlsldADDRPCREL; } // We create ADJCALLSTACKUP and ADJCALLSTACKDOWN around _tls_get_addr diff --git a/llvm/test/CodeGen/PowerPC/pcrel-tls_get_addr_clobbers.ll b/llvm/test/CodeGen/PowerPC/pcrel-tls_get_addr_clobbers.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/PowerPC/pcrel-tls_get_addr_clobbers.ll @@ -0,0 +1,25 @@ +; RUN: llc -verify-machineinstrs -mtriple="powerpc64le-unknown-linux-gnu" \ +; RUN: -ppc-asm-full-reg-names -mcpu=pwr10 -relocation-model=pic < %s | FileCheck %s + +%0 = type { i32 (...)**, %0* } +@x = external dso_local thread_local unnamed_addr global %0*, align 8 +define void @test(i8* %arg) { +; CHECK-LABEL: test: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: mflr r0 +; CHECK: std r30, -16(r1) +; CHECK-NEXT: std r0, 16(r1) +; CHECK-NEXT: stdu r1, -48(r1) +; CHECK-NEXT: mr r30, r3 +; CHECK-NEXT: paddi r3, 0, x@got@tlsld@pcrel, 1 +; CHECK-NEXT: bl __tls_get_addr@notoc(x@tlsld) +; CHECK-NEXT: paddi r3, r3, x@DTPREL, 0 +; CHECK-NEXT: std r30, 0(r3) +; CHECK-NEXT: addi r1, r1, 48 +; CHECK-NEXT: ld r0, 16(r1) +; CHECK-NEXT: ld r30, -16(r1) +; CHECK-NEXT: mtlr r0 +entry: + store i8* %arg, i8** bitcast (%0** @x to i8**), align 8 + ret void +}