diff options
author | Chris Dewhurst <chris.dewhurst@lero.ie> | 2016-03-09 18:20:21 +0000 |
---|---|---|
committer | Chris Dewhurst <chris.dewhurst@lero.ie> | 2016-03-09 18:20:21 +0000 |
commit | 52adb575e61763e27198df0661526c7d7f2c4eaa (patch) | |
tree | 12ece538df863e1eb7f06e093107ec8fa54de2bf /llvm/lib/Target/Sparc | |
parent | ef13c522b42f9bd6b4bc0fe53930bc1e20a21800 (diff) | |
download | bcm5719-llvm-52adb575e61763e27198df0661526c7d7f2c4eaa.tar.gz bcm5719-llvm-52adb575e61763e27198df0661526c7d7f2c4eaa.zip |
This change adds co-processor condition branching and conditional traps to the Sparc back-end.
This will allow inline assembler code to utilize these features, but no automatic lowering is provided, except for the previously provided @llvm.trap, which lowers to "ta 5".
The change also separates out the different assembly language syntaxes for V8 and V9 Sparc. Previously, only V9 Sparc assembly syntax was provided.
The change also corrects the selection order of trap disassembly, allowing, e.g. "ta %g0 + 15" to be rendered, more readably, as "ta 15", ignoring the %g0 register. This is per the sparc v8 and v9 manuals.
Check-in includes many extra unit tests to check this works correctly on both V8 and V9 Sparc processors.
Code Reviewed at http://reviews.llvm.org/D17960.
llvm-svn: 263044
Diffstat (limited to 'llvm/lib/Target/Sparc')
-rw-r--r-- | llvm/lib/Target/Sparc/AsmParser/SparcAsmParser.cpp | 8 | ||||
-rw-r--r-- | llvm/lib/Target/Sparc/Disassembler/SparcDisassembler.cpp | 47 | ||||
-rw-r--r-- | llvm/lib/Target/Sparc/InstPrinter/SparcInstPrinter.cpp | 22 | ||||
-rw-r--r-- | llvm/lib/Target/Sparc/Sparc.h | 35 | ||||
-rw-r--r-- | llvm/lib/Target/Sparc/SparcInstrAliases.td | 117 | ||||
-rw-r--r-- | llvm/lib/Target/Sparc/SparcInstrInfo.cpp | 22 | ||||
-rw-r--r-- | llvm/lib/Target/Sparc/SparcInstrInfo.td | 14 |
7 files changed, 223 insertions, 42 deletions
diff --git a/llvm/lib/Target/Sparc/AsmParser/SparcAsmParser.cpp b/llvm/lib/Target/Sparc/AsmParser/SparcAsmParser.cpp index 94f1e67f588..37410c9dcd8 100644 --- a/llvm/lib/Target/Sparc/AsmParser/SparcAsmParser.cpp +++ b/llvm/lib/Target/Sparc/AsmParser/SparcAsmParser.cpp @@ -636,8 +636,12 @@ bool SparcAsmParser::ParseInstruction(ParseInstructionInfo &Info, return Error(Loc, "unexpected token"); } - while (getLexer().is(AsmToken::Comma)) { - Parser.Lex(); // Eat the comma. + while (getLexer().is(AsmToken::Comma) || getLexer().is(AsmToken::Plus)) { + if (getLexer().is(AsmToken::Plus)) { + // Plus tokens are significant in software_traps (p83, sparcv8.pdf). We must capture them. + Operands.push_back(SparcOperand::CreateToken("+", Parser.getTok().getLoc())); + } + Parser.Lex(); // Eat the comma or plus. // Parse and remember the operand. if (parseOperand(Operands, Name) != MatchOperand_Success) { SMLoc Loc = getLexer().getLoc(); diff --git a/llvm/lib/Target/Sparc/Disassembler/SparcDisassembler.cpp b/llvm/lib/Target/Sparc/Disassembler/SparcDisassembler.cpp index 44d35764003..1dea379e14e 100644 --- a/llvm/lib/Target/Sparc/Disassembler/SparcDisassembler.cpp +++ b/llvm/lib/Target/Sparc/Disassembler/SparcDisassembler.cpp @@ -311,6 +311,8 @@ static DecodeStatus DecodeReturn(MCInst &MI, unsigned insn, uint64_t Address, const void *Decoder); static DecodeStatus DecodeSWAP(MCInst &Inst, unsigned insn, uint64_t Address, const void *Decoder); +static DecodeStatus DecodeTRAP(MCInst &Inst, unsigned insn, uint64_t Address, + const void *Decoder); #include "SparcGenDisassemblerTables.inc" @@ -346,6 +348,18 @@ DecodeStatus SparcDisassembler::getInstruction(MCInst &Instr, uint64_t &Size, return MCDisassembler::Fail; // Calling the auto-generated decoder function. + + if (STI.getFeatureBits()[Sparc::FeatureV9]) + { + Result = decodeInstruction(DecoderTableSparcV932, Instr, Insn, Address, this, STI); + } + else + { + Result = decodeInstruction(DecoderTableSparcV832, Instr, Insn, Address, this, STI); + } + if (Result != MCDisassembler::Fail) + return Result; + Result = decodeInstruction(DecoderTableSparc32, Instr, Insn, Address, this, STI); @@ -619,3 +633,36 @@ static DecodeStatus DecodeSWAP(MCInst &MI, unsigned insn, uint64_t Address, return MCDisassembler::Success; } + +static DecodeStatus DecodeTRAP(MCInst &MI, unsigned insn, uint64_t Address, + const void *Decoder) { + + unsigned rs1 = fieldFromInstruction(insn, 14, 5); + unsigned isImm = fieldFromInstruction(insn, 13, 1); + unsigned cc =fieldFromInstruction(insn, 25, 4); + unsigned rs2 = 0; + unsigned imm7 = 0; + if (isImm) + imm7 = fieldFromInstruction(insn, 0, 7); + else + rs2 = fieldFromInstruction(insn, 0, 5); + + // Decode RS1. + DecodeStatus status = DecodeIntRegsRegisterClass(MI, rs1, Address, Decoder); + if (status != MCDisassembler::Success) + return status; + + // Decode RS1 | IMM7. + if (isImm) + MI.addOperand(MCOperand::createImm(imm7)); + else { + status = DecodeIntRegsRegisterClass(MI, rs2, Address, Decoder); + if (status != MCDisassembler::Success) + return status; + } + + // Decode CC + MI.addOperand(MCOperand::createImm(cc)); + + return MCDisassembler::Success; +} diff --git a/llvm/lib/Target/Sparc/InstPrinter/SparcInstPrinter.cpp b/llvm/lib/Target/Sparc/InstPrinter/SparcInstPrinter.cpp index 5d714fe4da9..554f32745f8 100644 --- a/llvm/lib/Target/Sparc/InstPrinter/SparcInstPrinter.cpp +++ b/llvm/lib/Target/Sparc/InstPrinter/SparcInstPrinter.cpp @@ -115,8 +115,21 @@ void SparcInstPrinter::printOperand(const MCInst *MI, int opNum, } if (MO.isImm()) { - O << (int)MO.getImm(); - return; + switch (MI->getOpcode()) { + default: + O << (int)MO.getImm(); + return; + + case SP::TICCri: // Fall through + case SP::TICCrr: // Fall through + case SP::TRAPri: // Fall through + case SP::TRAPrr: // Fall through + case SP::TXCCri: // Fall through + case SP::TXCCrr: // Fall through + // Only seven-bit values up to 127. + O << ((int) MO.getImm() & 0x7f); + return; + } } assert(MO.isExpr() && "Unknown operand kind in printOperand"); @@ -166,6 +179,11 @@ void SparcInstPrinter::printCCOperand(const MCInst *MI, int opNum, // Make sure CC is a fp conditional flag. CC = (CC < 16) ? (CC + 16) : CC; break; + case SP::CBCOND: + case SP::CBCONDA: + // Make sure CC is a cp conditional flag. + CC = (CC < 32) ? (CC + 32) : CC; + break; } O << SPARCCondCodeToString((SPCC::CondCodes)CC); } diff --git a/llvm/lib/Target/Sparc/Sparc.h b/llvm/lib/Target/Sparc/Sparc.h index 96378d522dc..0a8272d8929 100644 --- a/llvm/lib/Target/Sparc/Sparc.h +++ b/llvm/lib/Target/Sparc/Sparc.h @@ -72,7 +72,24 @@ namespace llvm { FCC_UGE = 12+16, // Unordered or Greater or Equal FCC_LE = 13+16, // Less or Equal FCC_ULE = 14+16, // Unordered or Less or Equal - FCC_O = 15+16 // Ordered + FCC_O = 15+16, // Ordered + + CPCC_A = 8+32, // Always + CPCC_N = 0+32, // Never + CPCC_3 = 7+32, + CPCC_2 = 6+32, + CPCC_23 = 5+32, + CPCC_1 = 4+32, + CPCC_13 = 3+32, + CPCC_12 = 2+32, + CPCC_123 = 1+32, + CPCC_0 = 9+32, + CPCC_03 = 10+32, + CPCC_02 = 11+32, + CPCC_023 = 12+32, + CPCC_01 = 13+32, + CPCC_013 = 14+32, + CPCC_012 = 15+32 }; } @@ -110,6 +127,22 @@ namespace llvm { case SPCC::FCC_LE: return "le"; case SPCC::FCC_ULE: return "ule"; case SPCC::FCC_O: return "o"; + case SPCC::CPCC_A: return "a"; + case SPCC::CPCC_N: return "n"; + case SPCC::CPCC_3: return "3"; + case SPCC::CPCC_2: return "2"; + case SPCC::CPCC_23: return "23"; + case SPCC::CPCC_1: return "1"; + case SPCC::CPCC_13: return "13"; + case SPCC::CPCC_12: return "12"; + case SPCC::CPCC_123: return "123"; + case SPCC::CPCC_0: return "0"; + case SPCC::CPCC_03: return "03"; + case SPCC::CPCC_02: return "02"; + case SPCC::CPCC_023: return "023"; + case SPCC::CPCC_01: return "01"; + case SPCC::CPCC_013: return "013"; + case SPCC::CPCC_012: return "012"; } llvm_unreachable("Invalid cond code"); } diff --git a/llvm/lib/Target/Sparc/SparcInstrAliases.td b/llvm/lib/Target/Sparc/SparcInstrAliases.td index 361d21440a9..df570cea8da 100644 --- a/llvm/lib/Target/Sparc/SparcInstrAliases.td +++ b/llvm/lib/Target/Sparc/SparcInstrAliases.td @@ -136,59 +136,68 @@ multiclass int_cond_alias<string cond, int condVal> { (FMOVQ_XCC QFPRegs:$rd, QFPRegs:$rs2, condVal)>, Requires<[Is64Bit, HasHardQuad]>; - // t<cond> %icc, rs1 + rs2 - def : InstAlias<!strconcat(!strconcat("t", cond), " %icc, $rs1 + $rs2"), - (TICCrr IntRegs:$rs1, IntRegs:$rs2, condVal)>, - Requires<[HasV9]>; - // t<cond> %icc, rs => t<cond> %icc, G0 + rs def : InstAlias<!strconcat(!strconcat("t", cond), " %icc, $rs2"), (TICCrr G0, IntRegs:$rs2, condVal)>, Requires<[HasV9]>; - - // t<cond> %xcc, rs1 + rs2 - def : InstAlias<!strconcat(!strconcat("t", cond), " %xcc, $rs1 + $rs2"), - (TXCCrr IntRegs:$rs1, IntRegs:$rs2, condVal)>, + // t<cond> %icc, rs1 + rs2 + def : InstAlias<!strconcat(!strconcat("t", cond), " %icc, $rs1 + $rs2"), + (TICCrr IntRegs:$rs1, IntRegs:$rs2, condVal)>, Requires<[HasV9]>; + // t<cond> %xcc, rs => t<cond> %xcc, G0 + rs def : InstAlias<!strconcat(!strconcat("t", cond), " %xcc, $rs2"), (TXCCrr G0, IntRegs:$rs2, condVal)>, Requires<[HasV9]>; + // t<cond> %xcc, rs1 + rs2 + def : InstAlias<!strconcat(!strconcat("t", cond), " %xcc, $rs1 + $rs2"), + (TXCCrr IntRegs:$rs1, IntRegs:$rs2, condVal)>, + Requires<[HasV9]>; - // t<cond> rs1 + rs2 => t<cond> %icc, rs1 + rs2 - def : InstAlias<!strconcat(!strconcat("t", cond), " $rs1 + $rs2"), - (TICCrr IntRegs:$rs1, IntRegs:$rs2, condVal)>; // t<cond> rs=> t<cond> %icc, G0 + rs2 - def : InstAlias<!strconcat(!strconcat("t", cond), " $rs2"), - (TICCrr G0, IntRegs:$rs2, condVal)>; + //def : InstAlias<!strconcat(!strconcat("t", cond), " $rs2"), + // (TICCrr G0, IntRegs:$rs2, condVal)>, + // Requires<[HasV9]>; + + // t<cond> rs1 + rs2 => t<cond> %icc, rs1 + rs2 + //def : InstAlias<!strconcat(!strconcat("t", cond), " $rs1 + $rs2"), + // (TICCrr IntRegs:$rs1, IntRegs:$rs2, condVal)>, + // Requires<[HasV9]>; - // t<cond> %icc, rs1 + imm - def : InstAlias<!strconcat(!strconcat("t", cond), " %icc, $rs1 + $imm"), - (TICCri IntRegs:$rs1, i32imm:$imm, condVal)>, - Requires<[HasV9]>; // t<cond> %icc, imm => t<cond> %icc, G0 + imm def : InstAlias<!strconcat(!strconcat("t", cond), " %icc, $imm"), (TICCri G0, i32imm:$imm, condVal)>, Requires<[HasV9]>; - // t<cond> %xcc, rs1 + imm - def : InstAlias<!strconcat(!strconcat("t", cond), " %xcc, $rs1 + $imm"), - (TXCCri IntRegs:$rs1, i32imm:$imm, condVal)>, + // t<cond> %icc, rs1 + imm + def : InstAlias<!strconcat(!strconcat("t", cond), " %icc, $rs1 + $imm"), + (TICCri IntRegs:$rs1, i32imm:$imm, condVal)>, Requires<[HasV9]>; // t<cond> %xcc, imm => t<cond> %xcc, G0 + imm def : InstAlias<!strconcat(!strconcat("t", cond), " %xcc, $imm"), (TXCCri G0, i32imm:$imm, condVal)>, Requires<[HasV9]>; + // t<cond> %xcc, rs1 + imm + def : InstAlias<!strconcat(!strconcat("t", cond), " %xcc, $rs1 + $imm"), + (TXCCri IntRegs:$rs1, i32imm:$imm, condVal)>, + Requires<[HasV9]>; + + // t<cond> imm => t<cond> G0 + imm + def : InstAlias<!strconcat(!strconcat("t", cond), " $imm"), + (TRAPri G0, i32imm:$imm, condVal)>; - // t<cond> rs1 + imm => t<cond> %icc, rs1 + imm + // t<cond> rs1 + imm => t<cond> rs1 + imm def : InstAlias<!strconcat(!strconcat("t", cond), " $rs1 + $imm"), - (TICCri IntRegs:$rs1, i32imm:$imm, condVal)>; + (TRAPri IntRegs:$rs1, i32imm:$imm, condVal)>; - // t<cond> imm => t<cond> %icc, G0 + imm - def : InstAlias<!strconcat(!strconcat("t", cond), " $imm"), - (TICCri G0, i32imm:$imm, condVal)>; + // t<cond> rs1 => t<cond> G0 + rs1 + def : InstAlias<!strconcat(!strconcat("t", cond), " $rs1"), + (TRAPrr G0, IntRegs:$rs1, condVal)>; + // t<cond> rs1 + rs2 + def : InstAlias<!strconcat(!strconcat("t", cond), " $rs1 + $rs2"), + (TRAPrr IntRegs:$rs1, IntRegs:$rs2, condVal)>; } @@ -244,14 +253,23 @@ multiclass fp_cond_alias<string cond, int condVal> { Requires<[HasV9, HasHardQuad]>; } + +// Instruction aliases for co-processor conditional branches. +multiclass cp_cond_alias<string cond, int condVal> { + + // cb<cond> $imm + def : InstAlias<!strconcat(!strconcat("cb", cond), " $imm"), + (CBCOND brtarget:$imm, condVal), 0>; + + // cb<cond>,a $imm + def : InstAlias<!strconcat(!strconcat("cb", cond), ",a $imm"), + (CBCONDA brtarget:$imm, condVal), 0>; +} + defm : int_cond_alias<"a", 0b1000>; -defm : int_cond_alias<"", 0b1000>; // same as a; gnu asm, not in manual defm : int_cond_alias<"n", 0b0000>; defm : int_cond_alias<"ne", 0b1001>; -defm : int_cond_alias<"nz", 0b1001>; // same as ne defm : int_cond_alias<"e", 0b0001>; -defm : int_cond_alias<"eq", 0b0001>; // same as e -defm : int_cond_alias<"z", 0b0001>; // same as e defm : int_cond_alias<"g", 0b1010>; defm : int_cond_alias<"le", 0b0010>; defm : int_cond_alias<"ge", 0b1011>; @@ -259,16 +277,21 @@ defm : int_cond_alias<"l", 0b0011>; defm : int_cond_alias<"gu", 0b1100>; defm : int_cond_alias<"leu", 0b0100>; defm : int_cond_alias<"cc", 0b1101>; -defm : int_cond_alias<"geu", 0b1101>; // same as cc defm : int_cond_alias<"cs", 0b0101>; -defm : int_cond_alias<"lu", 0b0101>; // same as cs defm : int_cond_alias<"pos", 0b1110>; defm : int_cond_alias<"neg", 0b0110>; defm : int_cond_alias<"vc", 0b1111>; defm : int_cond_alias<"vs", 0b0111>; - +let EmitPriority = 0 in +{ + defm : int_cond_alias<"", 0b1000>; // same as a; gnu asm, not in manual + defm : int_cond_alias<"nz", 0b1001>; // same as ne + defm : int_cond_alias<"eq", 0b0001>; // same as e + defm : int_cond_alias<"z", 0b0001>; // same as e + defm : int_cond_alias<"geu", 0b1101>; // same as cc + defm : int_cond_alias<"lu", 0b0101>; // same as cs +} defm : fp_cond_alias<"a", 0b1000>; -defm : fp_cond_alias<"", 0b1000>; // same as a; gnu asm, not in manual defm : fp_cond_alias<"n", 0b0000>; defm : fp_cond_alias<"u", 0b0111>; defm : fp_cond_alias<"g", 0b0110>; @@ -277,15 +300,37 @@ defm : fp_cond_alias<"l", 0b0100>; defm : fp_cond_alias<"ul", 0b0011>; defm : fp_cond_alias<"lg", 0b0010>; defm : fp_cond_alias<"ne", 0b0001>; -defm : fp_cond_alias<"nz", 0b0001>; // same as ne defm : fp_cond_alias<"e", 0b1001>; -defm : fp_cond_alias<"z", 0b1001>; // same as e defm : fp_cond_alias<"ue", 0b1010>; defm : fp_cond_alias<"ge", 0b1011>; defm : fp_cond_alias<"uge", 0b1100>; defm : fp_cond_alias<"le", 0b1101>; defm : fp_cond_alias<"ule", 0b1110>; defm : fp_cond_alias<"o", 0b1111>; +let EmitPriority = 0 in +{ + defm : fp_cond_alias<"", 0b1000>; // same as a; gnu asm, not in manual + defm : fp_cond_alias<"nz", 0b0001>; // same as ne + defm : fp_cond_alias<"z", 0b1001>; // same as e +} + +defm : cp_cond_alias<"a", 0b1000>; +defm : cp_cond_alias<"n", 0b0000>; +defm : cp_cond_alias<"3", 0b0111>; +defm : cp_cond_alias<"2", 0b0110>; +defm : cp_cond_alias<"23", 0b0101>; +defm : cp_cond_alias<"1", 0b0100>; +defm : cp_cond_alias<"13", 0b0011>; +defm : cp_cond_alias<"12", 0b0010>; +defm : cp_cond_alias<"123", 0b0001>; +defm : cp_cond_alias<"0", 0b1001>; +defm : cp_cond_alias<"03", 0b1010>; +defm : cp_cond_alias<"02", 0b1011>; +defm : cp_cond_alias<"023", 0b1100>; +defm : cp_cond_alias<"01", 0b1101>; +defm : cp_cond_alias<"013", 0b1110>; +defm : cp_cond_alias<"012", 0b1111>; +let EmitPriority = 0 in defm : cp_cond_alias<"", 0b1000>; // same as a; gnu asm, not in manual // Section A.3 Synthetic Instructions diff --git a/llvm/lib/Target/Sparc/SparcInstrInfo.cpp b/llvm/lib/Target/Sparc/SparcInstrInfo.cpp index 0a123185ca6..28b81b608b3 100644 --- a/llvm/lib/Target/Sparc/SparcInstrInfo.cpp +++ b/llvm/lib/Target/Sparc/SparcInstrInfo.cpp @@ -119,6 +119,28 @@ static SPCC::CondCodes GetOppositeBranchCondition(SPCC::CondCodes CC) case SPCC::FCC_UE: return SPCC::FCC_LG; case SPCC::FCC_NE: return SPCC::FCC_E; case SPCC::FCC_E: return SPCC::FCC_NE; + + case SPCC::CPCC_A: return SPCC::CPCC_N; + case SPCC::CPCC_N: return SPCC::CPCC_A; + case SPCC::CPCC_3: // Fall through + case SPCC::CPCC_2: // Fall through + case SPCC::CPCC_23: // Fall through + case SPCC::CPCC_1: // Fall through + case SPCC::CPCC_13: // Fall through + case SPCC::CPCC_12: // Fall through + case SPCC::CPCC_123: // Fall through + case SPCC::CPCC_0: // Fall through + case SPCC::CPCC_03: // Fall through + case SPCC::CPCC_02: // Fall through + case SPCC::CPCC_023: // Fall through + case SPCC::CPCC_01: // Fall through + case SPCC::CPCC_013: // Fall through + case SPCC::CPCC_012: + // "Opposite" code is not meaningful, as we don't know + // what the CoProc condition means here. The cond-code will + // only be used in inline assembler, so this code should + // not be reached in a normal compilation pass. + llvm_unreachable("Meaningless inversion of co-processor cond code"); } llvm_unreachable("Invalid cond code"); } diff --git a/llvm/lib/Target/Sparc/SparcInstrInfo.td b/llvm/lib/Target/Sparc/SparcInstrInfo.td index de111246f62..269c9631f95 100644 --- a/llvm/lib/Target/Sparc/SparcInstrInfo.td +++ b/llvm/lib/Target/Sparc/SparcInstrInfo.td @@ -891,6 +891,17 @@ let isReturn = 1, isTerminator = 1, hasDelaySlot = 1, // Section B.27 - Trap on Integer Condition Codes Instruction +// conditional branch class: +let DecoderNamespace = "SparcV8", DecoderMethod = "DecodeTRAP", hasSideEffects = 1, Uses = [ICC], cc = 0b00 in +{ + def TRAPrr : TRAPSPrr<0b111010, (outs), (ins IntRegs:$rs1, IntRegs:$rs2, + CCOp:$cond), + "t$cond $rs1 + $rs2", []>; + def TRAPri : TRAPSPri<0b111010, (outs), (ins IntRegs:$rs1, i32imm:$imm, + CCOp:$cond), + "t$cond $rs1 + $imm", []>; +} + multiclass TRAP<string regStr> { def rr : TRAPSPrr<0b111010, (outs), (ins IntRegs:$rs1, IntRegs:$rs2, CCOp:$cond), @@ -900,9 +911,10 @@ multiclass TRAP<string regStr> { !strconcat(!strconcat("t$cond ", regStr), ", $rs1 + $imm"), []>; } -let hasSideEffects = 1, Uses = [ICC], cc = 0b00 in +let DecoderNamespace = "SparcV9", DecoderMethod = "DecodeTRAP", Predicates = [HasV9], hasSideEffects = 1, Uses = [ICC], cc = 0b00 in defm TICC : TRAP<"%icc">; + let isBarrier = 1, isTerminator = 1, rd = 0b01000, rs1 = 0, simm13 = 5 in def TA5 : F3_2<0b10, 0b111010, (outs), (ins), "ta 5", [(trap)]>; |