Index: llvm/lib/Target/Sparc/AsmParser/SparcAsmParser.cpp =================================================================== --- llvm/lib/Target/Sparc/AsmParser/SparcAsmParser.cpp +++ llvm/lib/Target/Sparc/AsmParser/SparcAsmParser.cpp @@ -82,6 +82,11 @@ OperandMatchResultTy parseMembarTag(OperandVector &Operands); + template + OperandMatchResultTy parseShiftAmtImm(OperandVector &Operands); + + OperandMatchResultTy parseCallTarget(OperandVector &Operands); + OperandMatchResultTy parseOperand(OperandVector &Operands, StringRef Name); OperandMatchResultTy @@ -262,6 +267,35 @@ bool isMEMri() const { return Kind == k_MemoryImm; } bool isMembarTag() const { return Kind == k_Immediate; } + bool isCallTarget() const { + if (!isImm()) + return false; + + if (const MCConstantExpr *CE = dyn_cast(Imm.Val)) + return CE->getValue() % 4 == 0; + + return true; + } + + bool isShiftAmtImm5() const { + if (!isImm()) + return false; + + if (const MCConstantExpr *CE = dyn_cast(Imm.Val)) + return isUInt<5>(CE->getValue()); + + return false; + } + bool isShiftAmtImm6() const { + if (!isImm()) + return false; + + if (const MCConstantExpr *CE = dyn_cast(Imm.Val)) + return isUInt<6>(CE->getValue()); + + return false; + } + bool isIntReg() const { return (Kind == k_Register && Reg.Kind == rk_IntReg); } @@ -343,6 +377,15 @@ addExpr(Inst, Expr); } + void addShiftAmtImm5Operands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + addExpr(Inst, getImm()); + } + void addShiftAmtImm6Operands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + addExpr(Inst, getImm()); + } + void addExpr(MCInst &Inst, const MCExpr *Expr) const{ // Add as immediate when possible. Null MCExpr = 0. if (!Expr) @@ -377,6 +420,11 @@ addExpr(Inst, Expr); } + void addCallTargetOperands(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(); @@ -645,7 +693,7 @@ EndLoc = Tok.getEndLoc(); RegNo = 0; if (getLexer().getKind() != AsmToken::Percent) - return MatchOperand_Success; + return MatchOperand_NoMatch; Parser.Lex(); unsigned regKind = SparcOperand::rk_None; if (matchRegisterName(Tok, RegNo, regKind)) { @@ -729,37 +777,74 @@ OperandMatchResultTy SparcAsmParser::parseMEMOperand(OperandVector &Operands) { SMLoc S, E; - unsigned BaseReg = 0; - if (ParseRegister(BaseReg, S, E)) { + std::unique_ptr LHS; + if (parseSparcAsmOperand(LHS) != MatchOperand_Success) return MatchOperand_NoMatch; + + // Single immediate operand + if (LHS->isImm()) { + Operands.push_back(SparcOperand::MorphToMEMri(Sparc::G0, std::move(LHS))); + return MatchOperand_Success; } - switch (getLexer().getKind()) { - default: return MatchOperand_NoMatch; + if (!LHS->isIntReg()) { + Error(LHS->getStartLoc(), "invalid register kind for this operand"); + return MatchOperand_ParseFail; + } - case AsmToken::Comma: - case AsmToken::RBrac: - case AsmToken::EndOfStatement: - Operands.push_back(SparcOperand::CreateMEMr(BaseReg, S, E)); - return MatchOperand_Success; + AsmToken Tok = getLexer().getTok(); + // The plus token may be followed by a register or an immediate value, the + // minus one is always interpreted as sign for the immediate value + if (Tok.is(AsmToken::Plus) || Tok.is(AsmToken::Minus)) { + (void)Parser.parseOptionalToken(AsmToken::Plus); + + std::unique_ptr RHS; + if (parseSparcAsmOperand(RHS) != MatchOperand_Success) + return MatchOperand_NoMatch; + + if (RHS->isReg() && !RHS->isIntReg()) { + Error(RHS->getStartLoc(), "invalid register kind for this operand"); + return MatchOperand_ParseFail; + } + + Operands.push_back( + RHS->isImm() + ? SparcOperand::MorphToMEMri(LHS->getReg(), std::move(RHS)) + : SparcOperand::MorphToMEMrr(LHS->getReg(), std::move(RHS))); - case AsmToken:: Plus: - Parser.Lex(); // Eat the '+' - break; - case AsmToken::Minus: - break; + return MatchOperand_Success; } - std::unique_ptr Offset; - OperandMatchResultTy ResTy = parseSparcAsmOperand(Offset); - if (ResTy != MatchOperand_Success || !Offset) + Operands.push_back(SparcOperand::CreateMEMr(LHS->getReg(), S, E)); + return MatchOperand_Success; +} + +template +OperandMatchResultTy SparcAsmParser::parseShiftAmtImm(OperandVector &Operands) { + SMLoc S = Parser.getTok().getLoc(); + SMLoc E = SMLoc::getFromPointer(S.getPointer() - 1); + + // This is a register, not an immediate + if (getLexer().getKind() == AsmToken::Percent) return MatchOperand_NoMatch; - Operands.push_back( - Offset->isImm() ? SparcOperand::MorphToMEMri(BaseReg, std::move(Offset)) - : SparcOperand::MorphToMEMrr(BaseReg, std::move(Offset))); + const MCExpr *Expr; + if (getParser().parseExpression(Expr)) + return MatchOperand_ParseFail; + + const MCConstantExpr *CE = dyn_cast(Expr); + if (!CE) { + Error(S, "constant expression expected"); + return MatchOperand_ParseFail; + } + + if (!isUInt(CE->getValue())) { + Error(S, "immediate shift value out of range"); + return MatchOperand_ParseFail; + } + Operands.push_back(SparcOperand::CreateImm(Expr, S, E)); return MatchOperand_Success; } @@ -809,6 +894,33 @@ return MatchOperand_Success; } +OperandMatchResultTy SparcAsmParser::parseCallTarget(OperandVector &Operands) { + SMLoc S = Parser.getTok().getLoc(); + SMLoc E = SMLoc::getFromPointer(S.getPointer() - 1); + + switch (getLexer().getKind()) { + default: + return MatchOperand_NoMatch; + case AsmToken::LParen: + case AsmToken::Integer: + case AsmToken::Identifier: + case AsmToken::Dot: + break; + } + + const MCExpr *DestValue; + if (getParser().parseExpression(DestValue)) + return MatchOperand_NoMatch; + + bool IsPic = getContext().getObjectFileInfo()->isPositionIndependent(); + SparcMCExpr::VariantKind Kind = + IsPic ? SparcMCExpr::VK_Sparc_WPLT30 : SparcMCExpr::VK_Sparc_WDISP30; + + const MCExpr *DestExpr = SparcMCExpr::create(Kind, DestValue, getContext()); + Operands.push_back(SparcOperand::CreateImm(DestExpr, S, E)); + return MatchOperand_Success; +} + OperandMatchResultTy SparcAsmParser::parseOperand(OperandVector &Operands, StringRef Mnemonic) { @@ -936,6 +1048,7 @@ } break; + case AsmToken::Plus: case AsmToken::Minus: case AsmToken::Integer: case AsmToken::LParen: @@ -1272,7 +1385,7 @@ SparcAsmParser::adjustPICRelocation(SparcMCExpr::VariantKind VK, const MCExpr *subExpr) { // When in PIC mode, "%lo(...)" and "%hi(...)" behave differently. - // If the expression refers contains _GLOBAL_OFFSETE_TABLE, it is + // If the expression refers contains _GLOBAL_OFFSET_TABLE, it is // actually a %pc10 or %pc22 relocation. Otherwise, they are interpreted // as %got10 or %got22 relocation. Index: llvm/lib/Target/Sparc/MCTargetDesc/SparcInstPrinter.cpp =================================================================== --- llvm/lib/Target/Sparc/MCTargetDesc/SparcInstPrinter.cpp +++ llvm/lib/Target/Sparc/MCTargetDesc/SparcInstPrinter.cpp @@ -141,24 +141,34 @@ void SparcInstPrinter::printMemOperand(const MCInst *MI, int opNum, const MCSubtargetInfo &STI, raw_ostream &O, const char *Modifier) { - printOperand(MI, opNum, STI, O); - // If this is an ADD operand, emit it like normal operands. if (Modifier && !strcmp(Modifier, "arith")) { + printOperand(MI, opNum, STI, O); O << ", "; - printOperand(MI, opNum+1, STI, O); + printOperand(MI, opNum + 1, STI, O); return; } - const MCOperand &MO = MI->getOperand(opNum+1); - if (MO.isReg() && MO.getReg() == SP::G0) - return; // don't print "+%g0" - if (MO.isImm() && MO.getImm() == 0) - return; // don't print "+0" + const MCOperand &Op1 = MI->getOperand(opNum); + const MCOperand &Op2 = MI->getOperand(opNum + 1); - O << "+"; + bool PrintedFirstOperand = false; + if (Op1.isReg() && Op1.getReg() != SP::G0) { + printOperand(MI, opNum, STI, O); + PrintedFirstOperand = true; + } - printOperand(MI, opNum+1, STI, O); + // Skip the second operand iff it adds nothing (literal 0 or %g0) and we've + // already printed the first one + const bool SkipSecondOperand = + PrintedFirstOperand && ((Op2.isReg() && Op2.getReg() == SP::G0) || + (Op2.isImm() && Op2.getImm() == 0)); + + if (!SkipSecondOperand) { + if (PrintedFirstOperand) + O << '+'; + printOperand(MI, opNum + 1, STI, O); + } } void SparcInstPrinter::printCCOperand(const MCInst *MI, int opNum, Index: llvm/lib/Target/Sparc/MCTargetDesc/SparcMCCodeEmitter.cpp =================================================================== --- llvm/lib/Target/Sparc/MCTargetDesc/SparcMCCodeEmitter.cpp +++ llvm/lib/Target/Sparc/MCTargetDesc/SparcMCCodeEmitter.cpp @@ -22,6 +22,7 @@ #include "llvm/MC/MCFixup.h" #include "llvm/MC/MCInst.h" #include "llvm/MC/MCInstrInfo.h" +#include "llvm/MC/MCObjectFileInfo.h" #include "llvm/MC/MCRegisterInfo.h" #include "llvm/MC/MCSubtargetInfo.h" #include "llvm/MC/MCSymbol.h" @@ -68,13 +69,15 @@ unsigned getMachineOpValue(const MCInst &MI, const MCOperand &MO, SmallVectorImpl &Fixups, const MCSubtargetInfo &STI) const; - unsigned getCallTargetOpValue(const MCInst &MI, unsigned OpNo, SmallVectorImpl &Fixups, const MCSubtargetInfo &STI) const; unsigned getBranchTargetOpValue(const MCInst &MI, unsigned OpNo, SmallVectorImpl &Fixups, const MCSubtargetInfo &STI) const; + unsigned getSImm13OpValue(const MCInst &MI, unsigned OpNo, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const; unsigned getBranchPredTargetOpValue(const MCInst &MI, unsigned OpNo, SmallVectorImpl &Fixups, const MCSubtargetInfo &STI) const; @@ -146,20 +149,51 @@ return 0; } +unsigned +SparcMCCodeEmitter::getSImm13OpValue(const MCInst &MI, unsigned OpNo, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const { + const MCOperand &MO = MI.getOperand(OpNo); + + if (MO.isImm()) + return MO.getImm(); + + if (MO.isExpr()) { + const MCExpr *Expr = MO.getExpr(); + + // Constant value, no fixup is needed + if (const MCConstantExpr *CE = dyn_cast(Expr)) + return CE->getValue(); + + MCFixupKind Kind; + if (const SparcMCExpr *SExpr = dyn_cast(Expr)) { + Kind = MCFixupKind(SExpr->getFixupKind()); + } else { + bool IsPic = Ctx.getObjectFileInfo()->isPositionIndependent(); + Kind = IsPic ? MCFixupKind(Sparc::fixup_sparc_got13) + : MCFixupKind(Sparc::fixup_sparc_13); + } + + Fixups.push_back(MCFixup::create(0, Expr, Kind)); + return 0; + } + + return MO.getImm(); +} + unsigned SparcMCCodeEmitter:: getCallTargetOpValue(const MCInst &MI, unsigned OpNo, SmallVectorImpl &Fixups, const MCSubtargetInfo &STI) const { const MCOperand &MO = MI.getOperand(OpNo); - if (MO.isReg() || MO.isImm()) - return getMachineOpValue(MI, MO, Fixups, STI); + const MCExpr *Expr = MO.getExpr(); + const SparcMCExpr *SExpr = dyn_cast(Expr); if (MI.getOpcode() == SP::TLS_CALL) { // No fixups for __tls_get_addr. Will emit for fixups for tls_symbol in // encodeInstruction. #ifndef NDEBUG // Verify that the callee is actually __tls_get_addr. - const SparcMCExpr *SExpr = dyn_cast(MO.getExpr()); assert(SExpr && SExpr->getSubExpr()->getKind() == MCExpr::SymbolRef && "Unexpected expression in TLS_CALL"); const MCSymbolRefExpr *SymExpr = cast(SExpr->getSubExpr()); @@ -169,15 +203,8 @@ return 0; } - MCFixupKind fixupKind = (MCFixupKind)Sparc::fixup_sparc_call30; - - if (const SparcMCExpr *SExpr = dyn_cast(MO.getExpr())) { - if (SExpr->getKind() == SparcMCExpr::VK_Sparc_WPLT30) - fixupKind = (MCFixupKind)Sparc::fixup_sparc_wplt30; - } - - Fixups.push_back(MCFixup::create(0, MO.getExpr(), fixupKind)); - + MCFixupKind Kind = MCFixupKind(SExpr->getFixupKind()); + Fixups.push_back(MCFixup::create(0, Expr, Kind)); return 0; } Index: llvm/lib/Target/Sparc/MCTargetDesc/SparcMCExpr.h =================================================================== --- llvm/lib/Target/Sparc/MCTargetDesc/SparcMCExpr.h +++ llvm/lib/Target/Sparc/MCTargetDesc/SparcMCExpr.h @@ -38,6 +38,7 @@ VK_Sparc_GOT13, VK_Sparc_13, VK_Sparc_WPLT30, + VK_Sparc_WDISP30, VK_Sparc_R_DISP32, VK_Sparc_TLS_GD_HI22, VK_Sparc_TLS_GD_LO10, Index: llvm/lib/Target/Sparc/MCTargetDesc/SparcMCExpr.cpp =================================================================== --- llvm/lib/Target/Sparc/MCTargetDesc/SparcMCExpr.cpp +++ llvm/lib/Target/Sparc/MCTargetDesc/SparcMCExpr.cpp @@ -43,6 +43,8 @@ { bool closeParen = true; switch (Kind) { + default: + llvm_unreachable("Unhandled SparcMCExpr::VariantKind"); case VK_Sparc_None: closeParen = false; break; case VK_Sparc_LO: OS << "%lo("; break; case VK_Sparc_HI: OS << "%hi("; break; @@ -59,6 +61,9 @@ case VK_Sparc_GOT10: OS << "%lo("; break; case VK_Sparc_GOT13: closeParen = false; break; case VK_Sparc_13: closeParen = false; break; + case VK_Sparc_WDISP30: + closeParen = false; + break; case VK_Sparc_WPLT30: closeParen = false; break; case VK_Sparc_R_DISP32: OS << "%r_disp32("; break; case VK_Sparc_TLS_GD_HI22: OS << "%tgd_hi22("; break; @@ -137,6 +142,8 @@ case VK_Sparc_GOT13: return Sparc::fixup_sparc_got13; case VK_Sparc_13: return Sparc::fixup_sparc_13; case VK_Sparc_WPLT30: return Sparc::fixup_sparc_wplt30; + case VK_Sparc_WDISP30: + return Sparc::fixup_sparc_call30; case VK_Sparc_TLS_GD_HI22: return Sparc::fixup_sparc_tls_gd_hi22; case VK_Sparc_TLS_GD_LO10: return Sparc::fixup_sparc_tls_gd_lo10; case VK_Sparc_TLS_GD_ADD: return Sparc::fixup_sparc_tls_gd_add; Index: llvm/lib/Target/Sparc/SparcAsmPrinter.cpp =================================================================== --- llvm/lib/Target/Sparc/SparcAsmPrinter.cpp +++ llvm/lib/Target/Sparc/SparcAsmPrinter.cpp @@ -80,7 +80,7 @@ } static MCOperand createPCXCallOP(MCSymbol *Label, MCContext &OutContext) { - return createSparcMCOperand(SparcMCExpr::VK_Sparc_None, Label, OutContext); + return createSparcMCOperand(SparcMCExpr::VK_Sparc_WDISP30, Label, OutContext); } static MCOperand createPCXRelExprOp(SparcMCExpr::VariantKind Kind, Index: llvm/lib/Target/Sparc/SparcISelLowering.cpp =================================================================== --- llvm/lib/Target/Sparc/SparcISelLowering.cpp +++ llvm/lib/Target/Sparc/SparcISelLowering.cpp @@ -941,7 +941,8 @@ // If the callee is a GlobalAddress node (quite common, every direct call is) // turn it into a TargetGlobalAddress node so that legalize doesn't hack it. // Likewise ExternalSymbol -> TargetExternalSymbol. - unsigned TF = isPositionIndependent() ? SparcMCExpr::VK_Sparc_WPLT30 : 0; + unsigned TF = isPositionIndependent() ? SparcMCExpr::VK_Sparc_WPLT30 + : SparcMCExpr::VK_Sparc_WDISP30; if (GlobalAddressSDNode *G = dyn_cast(Callee)) Callee = DAG.getTargetGlobalAddress(G->getGlobal(), dl, MVT::i32, 0, TF); else if (ExternalSymbolSDNode *E = dyn_cast(Callee)) @@ -1244,7 +1245,8 @@ // Likewise ExternalSymbol -> TargetExternalSymbol. SDValue Callee = CLI.Callee; bool hasReturnsTwice = hasReturnsTwiceAttr(DAG, Callee, CLI.CS); - unsigned TF = isPositionIndependent() ? SparcMCExpr::VK_Sparc_WPLT30 : 0; + unsigned TF = isPositionIndependent() ? SparcMCExpr::VK_Sparc_WPLT30 + : SparcMCExpr::VK_Sparc_WDISP30; if (GlobalAddressSDNode *G = dyn_cast(Callee)) Callee = DAG.getTargetGlobalAddress(G->getGlobal(), DL, PtrVT, 0, TF); else if (ExternalSymbolSDNode *E = dyn_cast(Callee)) Index: llvm/lib/Target/Sparc/SparcInstr64Bit.td =================================================================== --- llvm/lib/Target/Sparc/SparcInstr64Bit.td +++ llvm/lib/Target/Sparc/SparcInstr64Bit.td @@ -42,9 +42,9 @@ def : Pat<(i64 (and i64:$val, 0xffffffff)), (SRLri $val, 0)>; def : Pat<(i64 (sext_inreg i64:$val, i32)), (SRAri $val, 0)>; -defm SLLX : F3_S<"sllx", 0b100101, 1, shl, i64, I64Regs>; -defm SRLX : F3_S<"srlx", 0b100110, 1, srl, i64, I64Regs>; -defm SRAX : F3_S<"srax", 0b100111, 1, sra, i64, I64Regs>; +defm SLLX : F3_S<"sllx", 0b100101, 1, shl, i64, shift_imm6, I64Regs>; +defm SRLX : F3_S<"srlx", 0b100110, 1, srl, i64, shift_imm6, I64Regs>; +defm SRAX : F3_S<"srax", 0b100111, 1, sra, i64, shift_imm6, I64Regs>; } // Predicates = [Is64Bit] Index: llvm/lib/Target/Sparc/SparcInstrFormats.td =================================================================== --- llvm/lib/Target/Sparc/SparcInstrFormats.td +++ llvm/lib/Target/Sparc/SparcInstrFormats.td @@ -224,13 +224,13 @@ // Define rr and ri shift instructions with patterns. multiclass F3_S Op3Val, bit XVal, SDNode OpNode, - ValueType VT, RegisterClass RC, + ValueType VT, ValueType SIT, RegisterClass RC, InstrItinClass itin = IIC_iu_instr> { def rr : F3_Sr<2, Op3Val, XVal, (outs RC:$rd), (ins RC:$rs1, IntRegs:$rs2), !strconcat(OpcStr, " $rs1, $rs2, $rd"), [(set VT:$rd, (OpNode VT:$rs1, i32:$rs2))], itin>; - def ri : F3_Si<2, Op3Val, XVal, (outs RC:$rd), (ins RC:$rs1, i32imm:$shcnt), + def ri : F3_Si<2, Op3Val, XVal, (outs RC:$rd), (ins RC:$rs1, SIT:$shcnt), !strconcat(OpcStr, " $rs1, $shcnt, $rd"), [(set VT:$rd, (OpNode VT:$rs1, (i32 imm:$shcnt)))], itin>; Index: llvm/lib/Target/Sparc/SparcInstrInfo.td =================================================================== --- llvm/lib/Target/Sparc/SparcInstrInfo.td +++ llvm/lib/Target/Sparc/SparcInstrInfo.td @@ -113,6 +113,18 @@ def ADDRrr : ComplexPattern; def ADDRri : ComplexPattern; +// Constrained operands for the shift operations. +class ShiftAmtImmAsmOperand : AsmOperandClass { + let Name = "ShiftAmtImm" # Bits; + let ParserMethod = "parseShiftAmtImm<" # Bits # ">"; +} +def shift_imm5 : Operand { + let ParserMatchClass = ShiftAmtImmAsmOperand<5>; +} +def shift_imm6 : Operand { + let ParserMatchClass = ShiftAmtImmAsmOperand<6>; +} + // Address operands def SparcMEMrrAsmOperand : AsmOperandClass { let Name = "MEMrr"; @@ -160,13 +172,20 @@ let EncoderMethod = "getBranchOnRegTargetOpValue"; } +def SparcCallTargetAsmOperand : AsmOperandClass { + let Name = "CallTarget"; + let ParserMethod = "parseCallTarget"; +} + def calltarget : Operand { let EncoderMethod = "getCallTargetOpValue"; let DecoderMethod = "DecodeCall"; + let ParserMatchClass = SparcCallTargetAsmOperand; } def simm13Op : Operand { let DecoderMethod = "DecodeSIMM13"; + let EncoderMethod = "getSImm13OpValue"; } // Operand for printing out a condition code. @@ -691,9 +710,9 @@ } // Section B.12 - Shift Instructions, p. 107 -defm SLL : F3_12<"sll", 0b100101, shl, IntRegs, i32, simm13Op>; -defm SRL : F3_12<"srl", 0b100110, srl, IntRegs, i32, simm13Op>; -defm SRA : F3_12<"sra", 0b100111, sra, IntRegs, i32, simm13Op>; +defm SLL : F3_S<"sll", 0b100101, 0, shl, i32, shift_imm5, IntRegs>; +defm SRL : F3_S<"srl", 0b100110, 0, srl, i32, shift_imm5, IntRegs>; +defm SRA : F3_S<"sra", 0b100111, 0, sra, i32, shift_imm5, IntRegs>; // Section B.13 - Add Instructions, p. 108 defm ADD : F3_12<"add", 0b000000, add, IntRegs, i32, simm13Op>; Index: llvm/test/MC/Sparc/sparc-asm-errors.s =================================================================== --- llvm/test/MC/Sparc/sparc-asm-errors.s +++ llvm/test/MC/Sparc/sparc-asm-errors.s @@ -14,3 +14,9 @@ ! V8: instruction requires a CPU feature not currently enabled ! V9: invalid membar mask number membar -127 + +! Test the boundary checks on the shift amount + ! V8: immediate shift value out of range + sll %g1, 32, %g2 + ! V9: immediate shift value out of range + slx %g1, 64, %g2 Index: llvm/test/MC/Sparc/sparc-ctrl-instructions.s =================================================================== --- llvm/test/MC/Sparc/sparc-ctrl-instructions.s +++ llvm/test/MC/Sparc/sparc-ctrl-instructions.s @@ -18,6 +18,10 @@ ! CHECK-NEXT: ! fixup A - offset: 0, value: %lo(sym), kind: fixup_sparc_lo10 call %g1+%lo(sym) + ! CHECK-LABEL: .Ltmp0: + ! CHECK: call .Ltmp0-4 ! encoding: [0b01AAAAAA,A,A,A] + call . - 4 + ! CHECK: jmp %g1+%i2 ! encoding: [0x81,0xc0,0x40,0x1a] jmp %g1 + %i2 @@ -31,6 +35,9 @@ ! CHECK-NEXT: ! fixup A - offset: 0, value: %lo(sym), kind: fixup_sparc_lo10 jmp %g1+%lo(sym) + ! CHECK: jmp sym ! encoding: [0x81,0xc0,0b001AAAAA,A] + jmp sym + ! CHECK: jmpl %g1+%i2, %g2 ! encoding: [0x85,0xc0,0x40,0x1a] jmpl %g1 + %i2, %g2 Index: llvm/test/MC/Sparc/sparc-relocations.s =================================================================== --- llvm/test/MC/Sparc/sparc-relocations.s +++ llvm/test/MC/Sparc/sparc-relocations.s @@ -50,6 +50,10 @@ ! CHECK-NEXT: ! fixup A - offset: 0, value: sym, kind: fixup_sparc_13 or %g1, sym, %g3 + ! CHECK: or %g1, sym+4, %g3 ! encoding: [0x86,0x10,0b011AAAAA,A] + ! CHECK-NEXT: ! fixup A - offset: 0, value: sym+4, kind: fixup_sparc_13 + or %g1, (sym+4), %g3 + ! This test needs to placed last in the file ! CHECK: .half a-.Ltmp0 .half a - .