diff --git a/llvm/lib/Target/Sparc/AsmParser/SparcAsmParser.cpp b/llvm/lib/Target/Sparc/AsmParser/SparcAsmParser.cpp index 9bfee26db806d..bfb62cdae8d44 100644 --- a/llvm/lib/Target/Sparc/AsmParser/SparcAsmParser.cpp +++ b/llvm/lib/Target/Sparc/AsmParser/SparcAsmParser.cpp @@ -15,6 +15,7 @@ #include "llvm/MC/MCContext.h" #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCInst.h" +#include "llvm/MC/MCInstBuilder.h" #include "llvm/MC/MCInstrInfo.h" #include "llvm/MC/MCObjectFileInfo.h" #include "llvm/MC/MCParser/MCAsmLexer.h" @@ -28,6 +29,7 @@ #include "llvm/MC/TargetRegistry.h" #include "llvm/Support/Casting.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/MathExtras.h" #include "llvm/Support/SMLoc.h" #include "llvm/Support/raw_ostream.h" #include "llvm/TargetParser/Triple.h" @@ -119,6 +121,9 @@ class SparcAsmParser : public MCTargetAsmParser { bool expandSET(MCInst &Inst, SMLoc IDLoc, SmallVectorImpl &Instructions); + bool expandSETX(MCInst &Inst, SMLoc IDLoc, + SmallVectorImpl &Instructions); + SMLoc getLoc() const { return getParser().getTok().getLoc(); } public: @@ -643,6 +648,78 @@ bool SparcAsmParser::expandSET(MCInst &Inst, SMLoc IDLoc, return false; } +bool SparcAsmParser::expandSETX(MCInst &Inst, SMLoc IDLoc, + SmallVectorImpl &Instructions) { + MCOperand MCRegOp = Inst.getOperand(0); + MCOperand MCValOp = Inst.getOperand(1); + MCOperand MCTmpOp = Inst.getOperand(2); + assert(MCRegOp.isReg() && MCTmpOp.isReg()); + assert(MCValOp.isImm() || MCValOp.isExpr()); + + // the imm operand can be either an expression or an immediate. + bool IsImm = MCValOp.isImm(); + int64_t ImmValue = IsImm ? MCValOp.getImm() : 0; + + const MCExpr *ValExpr = IsImm ? MCConstantExpr::create(ImmValue, getContext()) + : MCValOp.getExpr(); + + // Very small immediates can be expressed directly as a single `or`. + if (IsImm && isInt<13>(ImmValue)) { + // or rd, val, rd + Instructions.push_back(MCInstBuilder(SP::ORri) + .addReg(MCRegOp.getReg()) + .addReg(Sparc::G0) + .addExpr(ValExpr)); + return false; + } + + // Otherwise, first we set the lower half of the register. + + // sethi %hi(val), rd + Instructions.push_back( + MCInstBuilder(SP::SETHIi) + .addReg(MCRegOp.getReg()) + .addExpr(adjustPICRelocation(SparcMCExpr::VK_Sparc_HI, ValExpr))); + // or rd, %lo(val), rd + Instructions.push_back( + MCInstBuilder(SP::ORri) + .addReg(MCRegOp.getReg()) + .addReg(MCRegOp.getReg()) + .addExpr(adjustPICRelocation(SparcMCExpr::VK_Sparc_LO, ValExpr))); + + // Small positive immediates can be expressed as a single `sethi`+`or` + // combination, so we can just return here. + if (IsImm && isUInt<32>(ImmValue)) + return false; + + // For bigger immediates, we need to generate the upper half, then shift and + // merge it with the lower half that has just been generated above. + + // sethi %hh(val), tmp + Instructions.push_back( + MCInstBuilder(SP::SETHIi) + .addReg(MCTmpOp.getReg()) + .addExpr(adjustPICRelocation(SparcMCExpr::VK_Sparc_HH, ValExpr))); + // or tmp, %hm(val), tmp + Instructions.push_back( + MCInstBuilder(SP::ORri) + .addReg(MCTmpOp.getReg()) + .addReg(MCTmpOp.getReg()) + .addExpr(adjustPICRelocation(SparcMCExpr::VK_Sparc_HM, ValExpr))); + // sllx tmp, 32, tmp + Instructions.push_back(MCInstBuilder(SP::SLLXri) + .addReg(MCTmpOp.getReg()) + .addReg(MCTmpOp.getReg()) + .addImm(32)); + // or tmp, rd, rd + Instructions.push_back(MCInstBuilder(SP::ORrr) + .addReg(MCRegOp.getReg()) + .addReg(MCTmpOp.getReg()) + .addReg(MCRegOp.getReg())); + + return false; +} + bool SparcAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, OperandVector &Operands, MCStreamer &Out, @@ -663,6 +740,10 @@ bool SparcAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, if (expandSET(Inst, IDLoc, Instructions)) return true; break; + case SP::SETX: + if (expandSETX(Inst, IDLoc, Instructions)) + return true; + break; } for (const MCInst &I : Instructions) { diff --git a/llvm/lib/Target/Sparc/SparcInstrAliases.td b/llvm/lib/Target/Sparc/SparcInstrAliases.td index 01c3696cc7bca..b2a22eb0bd45b 100644 --- a/llvm/lib/Target/Sparc/SparcInstrAliases.td +++ b/llvm/lib/Target/Sparc/SparcInstrAliases.td @@ -443,6 +443,13 @@ def : InstAlias<"save", (SAVErr G0, G0, G0)>; // def : InstAlias<"set $val, $rd", (ORri IntRegs:$rd, (SETHIi (HI22 imm:$val)), (LO10 imm:$val))>; def SET : AsmPseudoInst<(outs IntRegs:$rd), (ins i32imm:$val), "set $val, $rd">; +// setx value, tmp, rd +// (turns into a sequence of sethi+or+shift, depending on the value) +def SETX : AsmPseudoInst<(outs I64Regs:$rd), + (ins i64imm:$val, I64Regs:$tmp), + "setx $val, $tmp, $rd">, + Requires<[Is64Bit, HasV9]>; + // not rd -> xnor rd, %g0, rd def : InstAlias<"not $rd", (XNORrr IntRegs:$rd, IntRegs:$rd, G0), 0>; diff --git a/llvm/test/MC/Sparc/sparcv9-synthetic-instructions.s b/llvm/test/MC/Sparc/sparcv9-synthetic-instructions.s new file mode 100644 index 0000000000000..dfaab3fc9b15f --- /dev/null +++ b/llvm/test/MC/Sparc/sparcv9-synthetic-instructions.s @@ -0,0 +1,80 @@ +! RUN: not llvm-mc %s -arch=sparc -show-encoding 2>&1 | FileCheck %s --check-prefix=V8 +! RUN: llvm-mc %s -arch=sparcv9 -show-encoding | FileCheck %s --check-prefix=V9 + +! V8: error: instruction requires a CPU feature not currently enabled +! V8-NEXT: setx 1, %g1, %o1 +! V9: mov 1, %o1 ! encoding: [0x92,0x10,0x20,0x01] +setx 1, %g1, %o1 + +! V8: error: instruction requires a CPU feature not currently enabled +! V8-NEXT: setx (0+1), %g1, %o1 +! V9: mov 1, %o1 ! encoding: [0x92,0x10,0x20,0x01] +setx (0+1), %g1, %o1 + +! V8: error: instruction requires a CPU feature not currently enabled +! V8-NEXT: setx -1, %g1, %o1 +! V9: mov -1, %o1 ! encoding: [0x92,0x10,0x3f,0xff] +setx -1, %g1, %o1 + +! V8: error: instruction requires a CPU feature not currently enabled +! V8-NEXT: setx (0-1), %g1, %o1 +! V9: mov -1, %o1 ! encoding: [0x92,0x10,0x3f,0xff] +setx (0-1), %g1, %o1 + +! V8: error: instruction requires a CPU feature not currently enabled +! V8-NEXT: setx 0xffffffff, %g1, %o1 +! V9: sethi %hi(4294967295), %o1 ! encoding: [0x13,0b00AAAAAA,A,A] +! V9: ! fixup A - offset: 0, value: %hi(4294967295), kind: fixup_sparc_hi22 +! V9: or %o1, %lo(4294967295), %o1 ! encoding: [0x92,0x12,0b011000AA,A] +! V9: ! fixup A - offset: 0, value: %lo(4294967295), kind: fixup_sparc_lo10 +setx 0xffffffff, %g1, %o1 + +! V8: error: instruction requires a CPU feature not currently enabled +! V8-NEXT: setx (0xffff0000+0x0000ffff), %g1, %o1 +! V9: sethi %hi(4294967295), %o1 ! encoding: [0x13,0b00AAAAAA,A,A] +! V9: ! fixup A - offset: 0, value: %hi(4294967295), kind: fixup_sparc_hi22 +! V9: or %o1, %lo(4294967295), %o1 ! encoding: [0x92,0x12,0b011000AA,A] +! V9: ! fixup A - offset: 0, value: %lo(4294967295), kind: fixup_sparc_lo10 +setx (0xffff0000+0x0000ffff), %g1, %o1 + +! V8: error: instruction requires a CPU feature not currently enabled +! V8-NEXT: setx 0x0123456789abcdef, %g1, %o0 +! V9: sethi %hi(81985529216486895), %o0 ! encoding: [0x11,0b00AAAAAA,A,A] +! V9: ! fixup A - offset: 0, value: %hi(81985529216486895), kind: fixup_sparc_hi22 +! V9: or %o0, %lo(81985529216486895), %o0 ! encoding: [0x90,0x12,0b001000AA,A] +! V9: ! fixup A - offset: 0, value: %lo(81985529216486895), kind: fixup_sparc_lo10 +! V9: sethi %hh(81985529216486895), %g1 ! encoding: [0x03,0b00AAAAAA,A,A] +! V9: ! fixup A - offset: 0, value: %hh(81985529216486895), kind: fixup_sparc_hh +! V9: or %g1, %hm(81985529216486895), %g1 ! encoding: [0x82,0x10,0b011000AA,A] +! V9: ! fixup A - offset: 0, value: %hm(81985529216486895), kind: fixup_sparc_hm +! V9: sllx %g1, 32, %g1 ! encoding: [0x83,0x28,0x70,0x20] +! V9: or %g1, %o0, %o0 ! encoding: [0x90,0x10,0x40,0x08] +setx 0x0123456789abcdef, %g1, %o0 + +! V8: error: instruction requires a CPU feature not currently enabled +! V8-NEXT: setx (0x0123456700000000+0x0000000089abcdef), %g1, %o0 +! V9: sethi %hi(81985529216486895), %o0 ! encoding: [0x11,0b00AAAAAA,A,A] +! V9: ! fixup A - offset: 0, value: %hi(81985529216486895), kind: fixup_sparc_hi22 +! V9: or %o0, %lo(81985529216486895), %o0 ! encoding: [0x90,0x12,0b001000AA,A] +! V9: ! fixup A - offset: 0, value: %lo(81985529216486895), kind: fixup_sparc_lo10 +! V9: sethi %hh(81985529216486895), %g1 ! encoding: [0x03,0b00AAAAAA,A,A] +! V9: ! fixup A - offset: 0, value: %hh(81985529216486895), kind: fixup_sparc_hh +! V9: or %g1, %hm(81985529216486895), %g1 ! encoding: [0x82,0x10,0b011000AA,A] +! V9: ! fixup A - offset: 0, value: %hm(81985529216486895), kind: fixup_sparc_hm +! V9: sllx %g1, 32, %g1 ! encoding: [0x83,0x28,0x70,0x20] +! V9: or %g1, %o0, %o0 ! encoding: [0x90,0x10,0x40,0x08] +setx (0x0123456700000000+0x0000000089abcdef), %g1, %o0 + +! V8: error: instruction requires a CPU feature not currently enabled +! V8-NEXT: setx (.BB1-.BB0), %g1, %o0 +! V9: sethi %hi(.BB1-.BB0), %o0 ! encoding: [0x11,0b00AAAAAA,A,A] +! V9: ! fixup A - offset: 0, value: %hi(.BB1-.BB0), kind: fixup_sparc_hi22 +! V9: or %o0, %lo(.BB1-.BB0), %o0 ! encoding: [0x90,0x12,0b001000AA,A] +! V9: ! fixup A - offset: 0, value: %lo(.BB1-.BB0), kind: fixup_sparc_lo10 +! V9: sethi %hh(.BB1-.BB0), %g1 ! encoding: [0x03,0b00AAAAAA,A,A] +! V9: ! fixup A - offset: 0, value: %hh(.BB1-.BB0), kind: fixup_sparc_hh +! V9: or %g1, %hm(.BB1-.BB0), %g1 ! encoding: [0x82,0x10,0b011000AA,A] +! V9: ! fixup A - offset: 0, value: %hm(.BB1-.BB0), kind: fixup_sparc_hm +! V9: sllx %g1, 32, %g1 ! encoding: [0x83,0x28,0x70,0x20] +! V9: or %g1, %o0, %o0 ! encoding: [0x90,0x10,0x40,0x08] +setx (.BB1-.BB0), %g1, %o0