diff --git a/llvm/lib/Target/Sparc/AsmParser/SparcAsmParser.cpp b/llvm/lib/Target/Sparc/AsmParser/SparcAsmParser.cpp --- a/llvm/lib/Target/Sparc/AsmParser/SparcAsmParser.cpp +++ b/llvm/lib/Target/Sparc/AsmParser/SparcAsmParser.cpp @@ -55,6 +55,8 @@ class SparcAsmParser : public MCTargetAsmParser { MCAsmParser &Parser; + enum class TailRelocKind { Load_GOT, Add_TLS, Load_TLS, Call_TLS }; + /// @name Auto-generated Match Functions /// { @@ -83,6 +85,9 @@ OperandMatchResultTy parseMembarTag(OperandVector &Operands); + template + OperandMatchResultTy parseTailRelocSym(OperandVector &Operands); + template OperandMatchResultTy parseShiftAmtImm(OperandVector &Operands); @@ -113,6 +118,8 @@ bool expandSET(MCInst &Inst, SMLoc IDLoc, SmallVectorImpl &Instructions); + SMLoc getLoc() const { return getParser().getTok().getLoc(); } + public: SparcAsmParser(const MCSubtargetInfo &sti, MCAsmParser &parser, const MCInstrInfo &MII, @@ -267,6 +274,7 @@ bool isMEMrr() const { return Kind == k_MemoryReg; } bool isMEMri() const { return Kind == k_MemoryImm; } bool isMembarTag() const { return Kind == k_Immediate; } + bool isTailRelocSym() const { return Kind == k_Immediate; } bool isCallTarget() const { if (!isImm()) @@ -427,6 +435,11 @@ addExpr(Inst, getImm()); } + void addTailRelocSymOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + addExpr(Inst, getImm()); + } + static std::unique_ptr CreateToken(StringRef Str, SMLoc S) { auto Op = std::make_unique(k_Token); Op->Tok.Data = Str.data(); @@ -850,6 +863,98 @@ return MatchOperand_Success; } +template +OperandMatchResultTy +SparcAsmParser::parseTailRelocSym(OperandVector &Operands) { + SMLoc S = getLoc(); + SMLoc E = SMLoc::getFromPointer(S.getPointer() - 1); + + auto MatchesKind = [](SparcMCExpr::VariantKind VK) -> bool { + switch (Kind) { + case TailRelocKind::Load_GOT: + // Non-TLS relocations on ld (or ldx). + // ld [%rr + %rr], %rr, %rel(sym) + return VK == SparcMCExpr::VK_Sparc_GOTDATA_OP; + case TailRelocKind::Add_TLS: + // TLS relocations on add. + // add %rr, %rr, %rr, %rel(sym) + switch (VK) { + case SparcMCExpr::VK_Sparc_TLS_GD_ADD: + case SparcMCExpr::VK_Sparc_TLS_IE_ADD: + case SparcMCExpr::VK_Sparc_TLS_LDM_ADD: + case SparcMCExpr::VK_Sparc_TLS_LDO_ADD: + return true; + default: + return false; + } + case TailRelocKind::Load_TLS: + // TLS relocations on ld (or ldx). + // ld[x] %addr, %rr, %rel(sym) + switch (VK) { + case SparcMCExpr::VK_Sparc_TLS_IE_LD: + case SparcMCExpr::VK_Sparc_TLS_IE_LDX: + return true; + default: + return false; + } + case TailRelocKind::Call_TLS: + // TLS relocations on call. + // call sym, %rel(sym) + switch (VK) { + case SparcMCExpr::VK_Sparc_TLS_GD_CALL: + case SparcMCExpr::VK_Sparc_TLS_LDM_CALL: + return true; + default: + return false; + } + default: + llvm_unreachable("Unexpected kind parameter"); + } + }; + + if (getLexer().getKind() != AsmToken::Percent) { + Error(getLoc(), "expected '%' for operand modifier"); + return MatchOperand_ParseFail; + } + + const AsmToken Tok = Parser.getTok(); + getParser().Lex(); // Eat '%' + + if (getLexer().getKind() != AsmToken::Identifier) { + Error(getLoc(), "expected valid identifier for operand modifier"); + return MatchOperand_ParseFail; + } + + StringRef Name = getParser().getTok().getIdentifier(); + SparcMCExpr::VariantKind VK = SparcMCExpr::parseVariantKind(Name); + if (VK == SparcMCExpr::VK_Sparc_None) { + Error(getLoc(), "invalid operand modifier"); + return MatchOperand_ParseFail; + } + + if (!MatchesKind(VK)) { + // Did not match the specified set of relocation types, put '%' back. + getLexer().UnLex(Tok); + return MatchOperand_NoMatch; + } + + Parser.Lex(); // Eat the identifier. + if (getLexer().getKind() != AsmToken::LParen) { + Error(getLoc(), "expected '('"); + return MatchOperand_ParseFail; + } + + getParser().Lex(); // Eat '(' + const MCExpr *SubExpr; + if (getParser().parseParenExpression(SubExpr, E)) { + return MatchOperand_ParseFail; + } + + const MCExpr *Val = adjustPICRelocation(VK, SubExpr); + Operands.push_back(SparcOperand::CreateImm(Val, S, E)); + return MatchOperand_Success; +} + OperandMatchResultTy SparcAsmParser::parseMembarTag(OperandVector &Operands) { SMLoc S = Parser.getTok().getLoc(); const MCExpr *EVal; @@ -1409,10 +1514,27 @@ StringRef name = Tok.getString(); SparcMCExpr::VariantKind VK = SparcMCExpr::parseVariantKind(name); + switch (VK) { + case SparcMCExpr::VK_Sparc_None: + Error(getLoc(), "invalid operand modifier"); + return false; - if (VK == SparcMCExpr::VK_Sparc_None) + case SparcMCExpr::VK_Sparc_GOTDATA_OP: + case SparcMCExpr::VK_Sparc_TLS_GD_ADD: + case SparcMCExpr::VK_Sparc_TLS_GD_CALL: + case SparcMCExpr::VK_Sparc_TLS_IE_ADD: + case SparcMCExpr::VK_Sparc_TLS_IE_LD: + case SparcMCExpr::VK_Sparc_TLS_IE_LDX: + case SparcMCExpr::VK_Sparc_TLS_LDM_ADD: + case SparcMCExpr::VK_Sparc_TLS_LDM_CALL: + case SparcMCExpr::VK_Sparc_TLS_LDO_ADD: + // These are special-cased at tablegen level. return false; + default: + break; + } + Parser.Lex(); // Eat the identifier. if (Parser.getTok().getKind() != AsmToken::LParen) return false; diff --git a/llvm/lib/Target/Sparc/MCTargetDesc/SparcAsmBackend.cpp b/llvm/lib/Target/Sparc/MCTargetDesc/SparcAsmBackend.cpp --- a/llvm/lib/Target/Sparc/MCTargetDesc/SparcAsmBackend.cpp +++ b/llvm/lib/Target/Sparc/MCTargetDesc/SparcAsmBackend.cpp @@ -47,6 +47,9 @@ case Sparc::fixup_sparc_br16_14: return (Value >> 2) & 0x3fff; + case Sparc::fixup_sparc_hix22: + return (~Value >> 10) & 0x3fffff; + case Sparc::fixup_sparc_pc22: case Sparc::fixup_sparc_got22: case Sparc::fixup_sparc_tls_gd_hi22: @@ -60,6 +63,9 @@ case Sparc::fixup_sparc_13: return Value & 0x1fff; + case Sparc::fixup_sparc_lox10: + return (Value & 0x3ff) | 0x1c00; + case Sparc::fixup_sparc_pc10: case Sparc::fixup_sparc_got10: case Sparc::fixup_sparc_tls_gd_lo10: @@ -98,6 +104,9 @@ case Sparc::fixup_sparc_tls_ie_ld: case Sparc::fixup_sparc_tls_ie_ldx: case Sparc::fixup_sparc_tls_ie_add: + case Sparc::fixup_sparc_gotdata_lox10: + case Sparc::fixup_sparc_gotdata_hix22: + case Sparc::fixup_sparc_gotdata_op: return 0; } } @@ -189,7 +198,12 @@ { "fixup_sparc_tls_ie_ldx", 0, 0, 0 }, { "fixup_sparc_tls_ie_add", 0, 0, 0 }, { "fixup_sparc_tls_le_hix22", 0, 0, 0 }, - { "fixup_sparc_tls_le_lox10", 0, 0, 0 } + { "fixup_sparc_tls_le_lox10", 0, 0, 0 }, + { "fixup_sparc_hix22", 10, 22, 0 }, + { "fixup_sparc_lox10", 19, 13, 0 }, + { "fixup_sparc_gotdata_hix22", 0, 0, 0 }, + { "fixup_sparc_gotdata_lox10", 0, 0, 0 }, + { "fixup_sparc_gotdata_op", 0, 0, 0 }, }; const static MCFixupKindInfo InfosLE[Sparc::NumTargetFixupKinds] = { @@ -231,7 +245,12 @@ { "fixup_sparc_tls_ie_ldx", 0, 0, 0 }, { "fixup_sparc_tls_ie_add", 0, 0, 0 }, { "fixup_sparc_tls_le_hix22", 0, 0, 0 }, - { "fixup_sparc_tls_le_lox10", 0, 0, 0 } + { "fixup_sparc_tls_le_lox10", 0, 0, 0 }, + { "fixup_sparc_hix22", 0, 22, 0 }, + { "fixup_sparc_lox10", 0, 13, 0 }, + { "fixup_sparc_gotdata_hix22", 0, 0, 0 }, + { "fixup_sparc_gotdata_lox10", 0, 0, 0 }, + { "fixup_sparc_gotdata_op", 0, 0, 0 }, }; // Fixup kinds from .reloc directive are like R_SPARC_NONE. They do diff --git a/llvm/lib/Target/Sparc/MCTargetDesc/SparcELFObjectWriter.cpp b/llvm/lib/Target/Sparc/MCTargetDesc/SparcELFObjectWriter.cpp --- a/llvm/lib/Target/Sparc/MCTargetDesc/SparcELFObjectWriter.cpp +++ b/llvm/lib/Target/Sparc/MCTargetDesc/SparcELFObjectWriter.cpp @@ -112,6 +112,11 @@ case Sparc::fixup_sparc_tls_ie_add: return ELF::R_SPARC_TLS_IE_ADD; case Sparc::fixup_sparc_tls_le_hix22: return ELF::R_SPARC_TLS_LE_HIX22; case Sparc::fixup_sparc_tls_le_lox10: return ELF::R_SPARC_TLS_LE_LOX10; + case Sparc::fixup_sparc_hix22: return ELF::R_SPARC_HIX22; + case Sparc::fixup_sparc_lox10: return ELF::R_SPARC_LOX10; + case Sparc::fixup_sparc_gotdata_hix22: return ELF::R_SPARC_GOTDATA_HIX22; + case Sparc::fixup_sparc_gotdata_lox10: return ELF::R_SPARC_GOTDATA_LOX10; + case Sparc::fixup_sparc_gotdata_op: return ELF::R_SPARC_GOTDATA_OP; } return ELF::R_SPARC_NONE; diff --git a/llvm/lib/Target/Sparc/MCTargetDesc/SparcFixupKinds.h b/llvm/lib/Target/Sparc/MCTargetDesc/SparcFixupKinds.h --- a/llvm/lib/Target/Sparc/MCTargetDesc/SparcFixupKinds.h +++ b/llvm/lib/Target/Sparc/MCTargetDesc/SparcFixupKinds.h @@ -95,6 +95,18 @@ fixup_sparc_tls_le_hix22, fixup_sparc_tls_le_lox10, + /// 22-bit fixup corresponding to %hix(foo) + fixup_sparc_hix22, + /// 13-bit fixup corresponding to %lox(foo) + fixup_sparc_lox10, + + /// 22-bit fixup corresponding to %gdop_hix22(foo) + fixup_sparc_gotdata_hix22, + /// 13-bit fixup corresponding to %gdop_lox10(foo) + fixup_sparc_gotdata_lox10, + /// 32-bit fixup corresponding to %gdop(foo) + fixup_sparc_gotdata_op, + // Marker LastTargetFixupKind, NumTargetFixupKinds = LastTargetFixupKind - FirstTargetFixupKind diff --git a/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCCodeEmitter.cpp b/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCCodeEmitter.cpp --- a/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCCodeEmitter.cpp +++ b/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCCodeEmitter.cpp @@ -104,17 +104,21 @@ support::endian::write(OS, Bits, Ctx.getAsmInfo()->isLittleEndian() ? support::little : support::big); - unsigned tlsOpNo = 0; + + // Some instructions have phantom operands that only contribute a fixup entry. + unsigned SymOpNo = 0; switch (MI.getOpcode()) { default: break; - case SP::TLS_CALL: tlsOpNo = 1; break; + case SP::TLS_CALL: SymOpNo = 1; break; + case SP::GDOP_LDrr: + case SP::GDOP_LDXrr: case SP::TLS_ADDrr: case SP::TLS_ADDXrr: case SP::TLS_LDrr: - case SP::TLS_LDXrr: tlsOpNo = 3; break; + case SP::TLS_LDXrr: SymOpNo = 3; break; } - if (tlsOpNo != 0) { - const MCOperand &MO = MI.getOperand(tlsOpNo); + if (SymOpNo != 0) { + const MCOperand &MO = MI.getOperand(SymOpNo); uint64_t op = getMachineOpValue(MI, MO, Fixups, STI); assert(op == 0 && "Unexpected operand value!"); (void)op; // suppress warning. diff --git a/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCExpr.h b/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCExpr.h --- a/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCExpr.h +++ b/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCExpr.h @@ -58,7 +58,12 @@ VK_Sparc_TLS_IE_LDX, VK_Sparc_TLS_IE_ADD, VK_Sparc_TLS_LE_HIX22, - VK_Sparc_TLS_LE_LOX10 + VK_Sparc_TLS_LE_LOX10, + VK_Sparc_HIX22, + VK_Sparc_LOX10, + VK_Sparc_GOTDATA_HIX22, + VK_Sparc_GOTDATA_LOX10, + VK_Sparc_GOTDATA_OP, }; private: diff --git a/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCExpr.cpp b/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCExpr.cpp --- a/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCExpr.cpp +++ b/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCExpr.cpp @@ -81,6 +81,11 @@ case VK_Sparc_TLS_IE_ADD: OS << "%tie_add("; return true; case VK_Sparc_TLS_LE_HIX22: OS << "%tle_hix22("; return true; case VK_Sparc_TLS_LE_LOX10: OS << "%tle_lox10("; return true; + case VK_Sparc_HIX22: OS << "%hix("; return true; + case VK_Sparc_LOX10: OS << "%lox("; return true; + case VK_Sparc_GOTDATA_HIX22: OS << "%gdop_hix22("; return true; + case VK_Sparc_GOTDATA_LOX10: OS << "%gdop_lox10("; return true; + case VK_Sparc_GOTDATA_OP: OS << "%gdop("; return true; } llvm_unreachable("Unhandled SparcMCExpr::VariantKind"); } @@ -120,6 +125,11 @@ .Case("tie_add", VK_Sparc_TLS_IE_ADD) .Case("tle_hix22", VK_Sparc_TLS_LE_HIX22) .Case("tle_lox10", VK_Sparc_TLS_LE_LOX10) + .Case("hix", VK_Sparc_HIX22) + .Case("lox", VK_Sparc_LOX10) + .Case("gdop_hix22", VK_Sparc_GOTDATA_HIX22) + .Case("gdop_lox10", VK_Sparc_GOTDATA_LOX10) + .Case("gdop", VK_Sparc_GOTDATA_OP) .Default(VK_Sparc_None); } @@ -160,6 +170,11 @@ case VK_Sparc_TLS_IE_ADD: return Sparc::fixup_sparc_tls_ie_add; case VK_Sparc_TLS_LE_HIX22: return Sparc::fixup_sparc_tls_le_hix22; case VK_Sparc_TLS_LE_LOX10: return Sparc::fixup_sparc_tls_le_lox10; + case VK_Sparc_HIX22: return Sparc::fixup_sparc_hix22; + case VK_Sparc_LOX10: return Sparc::fixup_sparc_lox10; + case VK_Sparc_GOTDATA_HIX22: return Sparc::fixup_sparc_gotdata_hix22; + case VK_Sparc_GOTDATA_LOX10: return Sparc::fixup_sparc_gotdata_lox10; + case VK_Sparc_GOTDATA_OP: return Sparc::fixup_sparc_gotdata_op; } } diff --git a/llvm/lib/Target/Sparc/SparcISelLowering.h b/llvm/lib/Target/Sparc/SparcISelLowering.h --- a/llvm/lib/Target/Sparc/SparcISelLowering.h +++ b/llvm/lib/Target/Sparc/SparcISelLowering.h @@ -48,7 +48,9 @@ TLS_ADD, // For Thread Local Storage (TLS). TLS_LD, - TLS_CALL + TLS_CALL, + + LOAD_GDOP, // Load operation w/ gdop relocation. }; } diff --git a/llvm/lib/Target/Sparc/SparcISelLowering.cpp b/llvm/lib/Target/Sparc/SparcISelLowering.cpp --- a/llvm/lib/Target/Sparc/SparcISelLowering.cpp +++ b/llvm/lib/Target/Sparc/SparcISelLowering.cpp @@ -1900,6 +1900,7 @@ case SPISD::TLS_LD: return "SPISD::TLS_LD"; case SPISD::TLS_CALL: return "SPISD::TLS_CALL"; case SPISD::TAIL_CALL: return "SPISD::TAIL_CALL"; + case SPISD::LOAD_GDOP: return "SPISD::LOAD_GDOP"; } return nullptr; } diff --git a/llvm/lib/Target/Sparc/SparcInstr64Bit.td b/llvm/lib/Target/Sparc/SparcInstr64Bit.td --- a/llvm/lib/Target/Sparc/SparcInstr64Bit.td +++ b/llvm/lib/Target/Sparc/SparcInstr64Bit.td @@ -163,7 +163,7 @@ defm SUBX : F3_12<"sub", 0b000100, sub, I64Regs, i64, i64imm>; def TLS_ADDXrr : F3_1<2, 0b000000, (outs I64Regs:$rd), - (ins I64Regs:$rs1, I64Regs:$rs2, TLSSym:$sym), + (ins I64Regs:$rs1, I64Regs:$rs2, TailRelocSymTLSAdd:$sym), "add $rs1, $rs2, $rd, $sym", [(set i64:$rd, (tlsadd i64:$rs1, i64:$rs2, tglobaltlsaddr:$sym))]>; @@ -238,12 +238,20 @@ let DecoderMethod = "DecodeLoadInt" in defm LDX : Load<"ldx", 0b001011, load, I64Regs, i64>; -let mayLoad = 1, isAsmParserOnly = 1 in +let mayLoad = 1, isAsmParserOnly = 1 in { def TLS_LDXrr : F3_1<3, 0b001011, - (outs IntRegs:$dst), (ins MEMrr:$addr, TLSSym:$sym), + (outs IntRegs:$dst), + (ins MEMrr:$addr, TailRelocSymTLSLoad:$sym), "ldx [$addr], $dst, $sym", [(set i64:$dst, (tlsld ADDRrr:$addr, tglobaltlsaddr:$sym))]>; + def GDOP_LDXrr : F3_1<3, 0b001011, + (outs I64Regs:$dst), + (ins MEMrr:$addr, TailRelocSymGOTLoad:$sym), + "ldx [$addr], $dst, $sym", + [(set i64:$dst, + (load_gdop ADDRrr:$addr, tglobaladdr:$sym))]>; +} // Extending loads to i64. def : Pat<(i64 (zextloadi1 ADDRrr:$addr)), (LDUBrr ADDRrr:$addr)>; diff --git a/llvm/lib/Target/Sparc/SparcInstrInfo.td b/llvm/lib/Target/Sparc/SparcInstrInfo.td --- a/llvm/lib/Target/Sparc/SparcInstrInfo.td +++ b/llvm/lib/Target/Sparc/SparcInstrInfo.td @@ -147,7 +147,29 @@ let ParserMatchClass = SparcMEMriAsmOperand; } -def TLSSym : Operand; +// Represents a tail relocation operand for instructions such as add, ld, call. +class SparcTailRelocSymAsmOperand : AsmOperandClass { + let Name = "TailRelocSym" # Kind; + let RenderMethod = "addTailRelocSymOperands"; + let PredicateMethod = "isTailRelocSym"; + let ParserMethod = "parseTailRelocSym"; +} + +def TailRelocSymGOTLoad : Operand { + let ParserMatchClass = SparcTailRelocSymAsmOperand<"Load_GOT">; +} + +def TailRelocSymTLSAdd : Operand { + let ParserMatchClass = SparcTailRelocSymAsmOperand<"Add_TLS">; +} + +def TailRelocSymTLSLoad : Operand { + let ParserMatchClass = SparcTailRelocSymAsmOperand<"Load_TLS">; +} + +def TailRelocSymTLSCall : Operand { + let ParserMatchClass = SparcTailRelocSymAsmOperand<"Call_TLS">; +} def SparcMembarTagAsmOperand : AsmOperandClass { let Name = "MembarTag"; @@ -214,6 +236,9 @@ def SDTSPtlsld : SDTypeProfile<1, 2, [SDTCisPtrTy<0>, SDTCisPtrTy<1>]>; +def SDTSPloadgdop : +SDTypeProfile<1, 2, [SDTCisPtrTy<0>, SDTCisPtrTy<1>]>; + def SPcmpicc : SDNode<"SPISD::CMPICC", SDTSPcmpicc, [SDNPOutGlue]>; def SPcmpfcc : SDNode<"SPISD::CMPFCC", SDTSPcmpfcc, [SDNPOutGlue]>; def SPbricc : SDNode<"SPISD::BRICC", SDTSPbrcc, [SDNPHasChain, SDNPInGlue]>; @@ -265,6 +290,8 @@ [SDNPHasChain, SDNPOptInGlue, SDNPOutGlue, SDNPVariadic]>; +def load_gdop : SDNode<"SPISD::LOAD_GDOP", SDTSPloadgdop>; + def getPCX : Operand { let PrintMethod = "printGetPCX"; } @@ -587,6 +614,15 @@ } } +let mayLoad = 1, isAsmParserOnly = 1 in { + def GDOP_LDrr : F3_1<3, 0b000000, + (outs IntRegs:$dst), + (ins MEMrr:$addr, TailRelocSymGOTLoad:$sym), + "ld [$addr], $dst, $sym", + [(set i32:$dst, + (load_gdop ADDRrr:$addr, tglobaladdr:$sym))]>; +} + // Section B.4 - Store Integer Instructions, p. 95 let DecoderMethod = "DecodeStoreInt" in { defm STB : StoreA<"stb", 0b000101, 0b010101, truncstorei8, IntRegs, i32>; @@ -1369,21 +1405,24 @@ let isAsmParserOnly = 1 in { def TLS_ADDrr : F3_1<2, 0b000000, (outs IntRegs:$rd), - (ins IntRegs:$rs1, IntRegs:$rs2, TLSSym:$sym), + (ins IntRegs:$rs1, IntRegs:$rs2, TailRelocSymTLSAdd:$sym), "add $rs1, $rs2, $rd, $sym", [(set i32:$rd, (tlsadd i32:$rs1, i32:$rs2, tglobaltlsaddr:$sym))]>; -let mayLoad = 1 in +let mayLoad = 1 in { def TLS_LDrr : F3_1<3, 0b000000, - (outs IntRegs:$dst), (ins MEMrr:$addr, TLSSym:$sym), + (outs IntRegs:$dst), + (ins MEMrr:$addr, TailRelocSymTLSLoad:$sym), "ld [$addr], $dst, $sym", [(set i32:$dst, (tlsld ADDRrr:$addr, tglobaltlsaddr:$sym))]>; +} let Uses = [O6], isCall = 1, hasDelaySlot = 1 in def TLS_CALL : InstSP<(outs), - (ins calltarget:$disp, TLSSym:$sym, variable_ops), + (ins calltarget:$disp, TailRelocSymTLSCall:$sym, + variable_ops), "call $disp, $sym", [(tlscall texternalsym:$disp, tglobaltlsaddr:$sym)], IIC_jmp_or_call> { diff --git a/llvm/test/MC/Sparc/sparc-fixups.s b/llvm/test/MC/Sparc/sparc-fixups.s new file mode 100644 --- /dev/null +++ b/llvm/test/MC/Sparc/sparc-fixups.s @@ -0,0 +1,30 @@ +! RUN: llvm-mc %s -arch=sparcv9 -filetype=obj | llvm-objdump -dr - | FileCheck %s +.text + +! Check that fixups are correctly applied. + +.set sym, 0xfedcba98 + +! CHECK: sethi 4175662, %o0 +sethi %hi(sym), %o0 +! CHECK: xor %o0, 664, %o0 +xor %o0, %lo(sym), %o0 + +! CHECK: sethi 1019, %o0 +sethi %h44(sym), %o0 +! CHECK: or %o0, 459, %o0 +or %o0, %m44(sym), %o0 +! CHECK: ld [%o0+2712], %o0 +ld [%o0 + %l44(sym)], %o0 + +! CHECK: sethi 0, %o0 +sethi %hh(sym), %o0 +! CHECK: sethi 4175662, %o0 +sethi %lm(sym), %o0 +! CHECK: or %o0, 0, %o0 +or %o0, %hm(sym), %o0 + +! CHECK: sethi 18641, %o0 +sethi %hix(sym), %o0 +! CHECK: xor %o0, -360, %o0 +xor %o0, %lox(sym), %o0 diff --git a/llvm/test/MC/Sparc/sparc-relocations.s b/llvm/test/MC/Sparc/sparc-relocations.s --- a/llvm/test/MC/Sparc/sparc-relocations.s +++ b/llvm/test/MC/Sparc/sparc-relocations.s @@ -2,18 +2,24 @@ ! RUN: llvm-mc %s -arch=sparcv9 -filetype=obj | llvm-readobj -r - | FileCheck %s --check-prefix=CHECK-OBJ ! CHECK-OBJ: Format: elf64-sparc - ! CHECK-OBJ: Relocations [ - ! CHECK-OBJ: 0x{{[0-9,A-F]+}} R_SPARC_WDISP30 foo - ! CHECK-OBJ: 0x{{[0-9,A-F]+}} R_SPARC_LO10 sym - ! CHECK-OBJ: 0x{{[0-9,A-F]+}} R_SPARC_HI22 sym - ! CHECK-OBJ: 0x{{[0-9,A-F]+}} R_SPARC_H44 sym - ! CHECK-OBJ: 0x{{[0-9,A-F]+}} R_SPARC_M44 sym - ! CHECK-OBJ: 0x{{[0-9,A-F]+}} R_SPARC_L44 sym - ! CHECK-OBJ: 0x{{[0-9,A-F]+}} R_SPARC_HH22 sym - ! CHECK-OBJ: 0x{{[0-9,A-F]+}} R_SPARC_HM10 sym - ! CHECK-OBJ: 0x{{[0-9,A-F]+}} R_SPARC_LM22 sym - ! CHECK-OBJ: 0x{{[0-9,A-F]+}} R_SPARC_13 sym - ! CHECK-ELF: ] + ! CHECK-OBJ: .rela.text { + ! CHECK-OBJ-NEXT: 0x{{[0-9,A-F]+}} R_SPARC_WDISP30 foo + ! CHECK-OBJ-NEXT: 0x{{[0-9,A-F]+}} R_SPARC_LO10 sym + ! CHECK-OBJ-NEXT: 0x{{[0-9,A-F]+}} R_SPARC_HI22 sym + ! CHECK-OBJ-NEXT: 0x{{[0-9,A-F]+}} R_SPARC_H44 sym + ! CHECK-OBJ-NEXT: 0x{{[0-9,A-F]+}} R_SPARC_M44 sym + ! CHECK-OBJ-NEXT: 0x{{[0-9,A-F]+}} R_SPARC_L44 sym + ! CHECK-OBJ-NEXT: 0x{{[0-9,A-F]+}} R_SPARC_HH22 sym + ! CHECK-OBJ-NEXT: 0x{{[0-9,A-F]+}} R_SPARC_HM10 sym + ! CHECK-OBJ-NEXT: 0x{{[0-9,A-F]+}} R_SPARC_LM22 sym + ! CHECK-OBJ-NEXT: 0x{{[0-9,A-F]+}} R_SPARC_13 sym + ! CHECK-OBJ-NEXT: 0x{{[0-9,A-F]+}} R_SPARC_13 sym + ! CHECK-OBJ-NEXT: 0x{{[0-9,A-F]+}} R_SPARC_HIX22 sym + ! CHECK-OBJ-NEXT: 0x{{[0-9,A-F]+}} R_SPARC_LOX10 sym + ! CHECK-OBJ-NEXT: 0x{{[0-9,A-F]+}} R_SPARC_GOTDATA_HIX22 sym + ! CHECK-OBJ-NEXT: 0x{{[0-9,A-F]+}} R_SPARC_GOTDATA_LOX10 sym + ! CHECK-OBJ-NEXT: 0x{{[0-9,A-F]+}} R_SPARC_GOTDATA_OP sym + ! CHECK-OBJ-NEXT: } ! CHECK: call foo ! encoding: [0b01AAAAAA,A,A,A] ! CHECK: ! fixup A - offset: 0, value: foo, kind: fixup_sparc_call30 @@ -59,6 +65,26 @@ ! CHECK-NEXT: ! fixup A - offset: 0, value: sym+4, kind: fixup_sparc_13 or %g1, (sym+4), %g3 + ! CHECK: sethi %hix(sym), %g1 ! encoding: [0x03,0b00AAAAAA,A,A] + ! CHECK-NEXT: ! fixup A - offset: 0, value: %hix(sym), kind: fixup_sparc_hix22 + sethi %hix(sym), %g1 + + ! CHECK: xor %g1, %lox(sym), %g1 ! encoding: [0x82,0x18,0b011AAAAA,A] + ! CHECK-NEXT: ! fixup A - offset: 0, value: %lox(sym), kind: fixup_sparc_lox10 + xor %g1, %lox(sym), %g1 + + ! CHECK: sethi %gdop_hix22(sym), %l1 ! encoding: [0x23,0x00,0x00,0x00] + ! CHECK-NEXT: ! fixup A - offset: 0, value: %gdop_hix22(sym), kind: fixup_sparc_gotdata_hix22 + sethi %gdop_hix22(sym), %l1 + + ! CHECK: or %l1, %gdop_lox10(sym), %l1 ! encoding: [0xa2,0x14,0x60,0x00] + ! CHECK-NEXT: ! fixup A - offset: 0, value: %gdop_lox10(sym), kind: fixup_sparc_gotdata_lox10 + or %l1, %gdop_lox10(sym), %l1 + + ! CHECK: ldx [%l7+%l1], %l2, %gdop(sym) ! encoding: [0xe4,0x5d,0xc0,0x11] + ! CHECK-NEXT: ! fixup A - offset: 0, value: %gdop(sym), kind: fixup_sparc_gotdata_op + ldx [%l7 + %l1], %l2, %gdop(sym) + ! This test needs to placed last in the file ! CHECK: .half a-.Ltmp0 .half a - .