Teach the MC and disassembler about SoftFail, and hook it up to UNPREDICTABLE on ARM. Wire this to tBLX in order to provide test coverage.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@150169 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
James Molloy 2012-02-09 10:56:31 +00:00
parent f41ab77847
commit 3015dfb7d7
4 changed files with 90 additions and 2 deletions

View File

@ -290,6 +290,14 @@ class InstTemplate<AddrMode am, int sz, IndexMode im,
class Encoding {
field bits<32> Inst;
// Mask of bits that cause an encoding to be UNPREDICTABLE.
// If a bit is set, then if the corresponding bit in the
// target encoding differs from its value in the "Inst" field,
// the instruction is UNPREDICTABLE (SoftFail in abstract parlance).
field bits<32> Unpredictable = 0;
// SoftFail is the generic name for this field, but we alias it so
// as to make it more obvious what it means in ARM-land.
field bits<32> SoftFail = Unpredictable;
}
class InstARM<AddrMode am, int sz, IndexMode im,

View File

@ -387,6 +387,7 @@ let isBranch = 1, isTerminator = 1, isBarrier = 1, isIndirectBranch = 1 in {
bits<4> Rm;
let Inst{6-3} = Rm;
let Inst{2-0} = 0b000;
let Unpredictable{2-0} = 0b111;
}
}

View File

@ -0,0 +1,5 @@
# RUN: llvm-mc --disassemble %s -triple=thumbv7 |& FileCheck %s
0x01 0x47
# CHECK: 3:1: warning: potentially undefined
# CHECK: bx r0

View File

@ -17,6 +17,7 @@
#include "FixedLenDecoderEmitter.h"
#include "CodeGenTarget.h"
#include "llvm/TableGen/Record.h"
#include "llvm/ADT/APInt.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
@ -285,9 +286,20 @@ protected:
void insnWithID(insn_t &Insn, unsigned Opcode) const {
BitsInit &Bits = getBitsField(*AllInstructions[Opcode]->TheDef, "Inst");
for (unsigned i = 0; i < BitWidth; ++i)
// We may have a SoftFail bitmask, which specifies a mask where an encoding
// may differ from the value in "Inst" and yet still be valid, but the
// disassembler should return SoftFail instead of Success.
//
// This is used for marking UNPREDICTABLE instructions in the ARM world.
BitsInit *SFBits = AllInstructions[Opcode]->TheDef->getValueAsBitsInit("SoftFail");
for (unsigned i = 0; i < BitWidth; ++i) {
if (SFBits && bitFromBits(*SFBits, i) == BIT_TRUE)
Insn.push_back(BIT_UNSET);
else
Insn.push_back(bitFromBits(Bits, i));
}
}
// Returns the record name.
const std::string &nameWithID(unsigned Opcode) const {
@ -334,6 +346,8 @@ protected:
// Returns true if predicate matches were emitted, false otherwise.
bool emitPredicateMatch(raw_ostream &o, unsigned &Indentation,unsigned Opc);
void emitSoftFailCheck(raw_ostream &o, unsigned Indentation, unsigned Opc);
// Emits code to decode the singleton. Return true if we have matched all the
// well-known bits.
bool emitSingletonDecoder(raw_ostream &o, unsigned &Indentation,unsigned Opc);
@ -800,6 +814,64 @@ bool FilterChooser::emitPredicateMatch(raw_ostream &o, unsigned &Indentation,
return Predicates->getSize() > 0;
}
void FilterChooser::emitSoftFailCheck(raw_ostream &o, unsigned Indentation, unsigned Opc) {
BitsInit *SFBits = AllInstructions[Opc]->TheDef->getValueAsBitsInit("SoftFail");
if (!SFBits) return;
BitsInit *InstBits = AllInstructions[Opc]->TheDef->getValueAsBitsInit("Inst");
APInt PositiveMask(BitWidth, 0ULL);
APInt NegativeMask(BitWidth, 0ULL);
for (unsigned i = 0; i < BitWidth; ++i) {
bit_value_t B = bitFromBits(*SFBits, i);
bit_value_t IB = bitFromBits(*InstBits, i);
if (B != BIT_TRUE) continue;
switch (IB) {
case BIT_FALSE:
// The bit is meant to be false, so emit a check to see if it is true.
PositiveMask.setBit(i);
break;
case BIT_TRUE:
// The bit is meant to be true, so emit a check to see if it is false.
NegativeMask.setBit(i);
break;
default:
// The bit is not set; this must be an error!
StringRef Name = AllInstructions[Opc]->TheDef->getName();
errs() << "SoftFail Conflict: bit SoftFail{" << i << "} in "
<< Name
<< " is set but Inst{" << i <<"} is unset!\n"
<< " - You can only mark a bit as SoftFail if it is fully defined"
<< " (1/0 - not '?') in Inst\n";
o << "#error SoftFail Conflict, " << Name << "::SoftFail{" << i
<< "} set but Inst{" << i << "} undefined!\n";
}
}
bool NeedPositiveMask = PositiveMask.getBoolValue();
bool NeedNegativeMask = NegativeMask.getBoolValue();
if (!NeedPositiveMask && !NeedNegativeMask)
return;
std::string PositiveMaskStr = PositiveMask.toString(16, /*signed=*/false);
std::string NegativeMaskStr = NegativeMask.toString(16, /*signed=*/false);
StringRef BitExt = "";
if (BitWidth > 32)
BitExt = "ULL";
o.indent(Indentation) << "if (";
if (NeedPositiveMask)
o << "insn & 0x" << PositiveMaskStr << BitExt;
if (NeedPositiveMask && NeedNegativeMask)
o << " || ";
if (NeedNegativeMask)
o << "~insn & 0x" << NegativeMaskStr << BitExt;
o << ")\n";
o.indent(Indentation+2) << "S = MCDisassembler::SoftFail;\n";
}
// Emits code to decode the singleton. Return true if we have matched all the
// well-known bits.
bool FilterChooser::emitSingletonDecoder(raw_ostream &o, unsigned &Indentation,
@ -822,6 +894,7 @@ bool FilterChooser::emitSingletonDecoder(raw_ostream &o, unsigned &Indentation,
if (!emitPredicateMatch(o, Indentation, Opc))
o << "1";
o << ") {\n";
emitSoftFailCheck(o, Indentation+2, Opc);
o.indent(Indentation) << " MI.setOpcode(" << Opc << ");\n";
std::vector<OperandInfo>& InsnOperands = Operands[Opc];
for (std::vector<OperandInfo>::iterator
@ -871,6 +944,7 @@ bool FilterChooser::emitSingletonDecoder(raw_ostream &o, unsigned &Indentation,
else
o << ") {\n";
}
emitSoftFailCheck(o, Indentation+2, Opc);
o.indent(Indentation) << " MI.setOpcode(" << Opc << ");\n";
std::vector<OperandInfo>& InsnOperands = Operands[Opc];
for (std::vector<OperandInfo>::iterator