Merge llvm, clang, compiler-rt, libc++, lld and lldb release_40 branch
r293807, and update build glue.
This commit is contained in:
commit
077e1117dc
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/projects/clang400-import/; revision=313067
@ -559,7 +559,6 @@ public:
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
template <class _Fp>
|
template <class _Fp>
|
||||||
inline _LIBCPP_INLINE_VISIBILITY
|
|
||||||
void
|
void
|
||||||
__call_once_proxy(void* __vp)
|
__call_once_proxy(void* __vp)
|
||||||
{
|
{
|
||||||
|
@ -480,6 +480,12 @@ class AsmPrinter : public MachineFunctionPass {
|
|||||||
/// Get the value for DW_AT_APPLE_isa. Zero if no isa encoding specified.
|
/// Get the value for DW_AT_APPLE_isa. Zero if no isa encoding specified.
|
||||||
virtual unsigned getISAEncoding() { return 0; }
|
virtual unsigned getISAEncoding() { return 0; }
|
||||||
|
|
||||||
|
/// Emit the directive and value for debug thread local expression
|
||||||
|
///
|
||||||
|
/// \p Value - The value to emit.
|
||||||
|
/// \p Size - The size of the integer (in bytes) to emit.
|
||||||
|
virtual void EmitDebugValue(const MCExpr *Value, unsigned Size) const;
|
||||||
|
|
||||||
//===------------------------------------------------------------------===//
|
//===------------------------------------------------------------------===//
|
||||||
// Dwarf Lowering Routines
|
// Dwarf Lowering Routines
|
||||||
//===------------------------------------------------------------------===//
|
//===------------------------------------------------------------------===//
|
||||||
|
@ -305,7 +305,7 @@ class SelectionDAGISel : public MachineFunctionPass {
|
|||||||
std::vector<unsigned> OpcodeOffset;
|
std::vector<unsigned> OpcodeOffset;
|
||||||
|
|
||||||
void UpdateChains(SDNode *NodeToMatch, SDValue InputChain,
|
void UpdateChains(SDNode *NodeToMatch, SDValue InputChain,
|
||||||
const SmallVectorImpl<SDNode *> &ChainNodesMatched,
|
SmallVectorImpl<SDNode *> &ChainNodesMatched,
|
||||||
bool isMorphNodeTo);
|
bool isMorphNodeTo);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -567,6 +567,15 @@ void AsmPrinter::EmitGlobalVariable(const GlobalVariable *GV) {
|
|||||||
OutStreamer->AddBlankLine();
|
OutStreamer->AddBlankLine();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Emit the directive and value for debug thread local expression
|
||||||
|
///
|
||||||
|
/// \p Value - The value to emit.
|
||||||
|
/// \p Size - The size of the integer (in bytes) to emit.
|
||||||
|
void AsmPrinter::EmitDebugValue(const MCExpr *Value,
|
||||||
|
unsigned Size) const {
|
||||||
|
OutStreamer->EmitValue(Value, Size);
|
||||||
|
}
|
||||||
|
|
||||||
/// EmitFunctionHeader - This method emits the header for the current
|
/// EmitFunctionHeader - This method emits the header for the current
|
||||||
/// function.
|
/// function.
|
||||||
void AsmPrinter::EmitFunctionHeader() {
|
void AsmPrinter::EmitFunctionHeader() {
|
||||||
|
@ -484,7 +484,7 @@ void DIEInteger::print(raw_ostream &O) const {
|
|||||||
/// EmitValue - Emit expression value.
|
/// EmitValue - Emit expression value.
|
||||||
///
|
///
|
||||||
void DIEExpr::EmitValue(const AsmPrinter *AP, dwarf::Form Form) const {
|
void DIEExpr::EmitValue(const AsmPrinter *AP, dwarf::Form Form) const {
|
||||||
AP->OutStreamer->EmitValue(Expr, SizeOf(AP, Form));
|
AP->EmitDebugValue(Expr, SizeOf(AP, Form));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// SizeOf - Determine size of expression value in bytes.
|
/// SizeOf - Determine size of expression value in bytes.
|
||||||
|
@ -174,7 +174,7 @@ static bool isDeInterleaveMask(ArrayRef<int> Mask, unsigned &Factor,
|
|||||||
/// I.e. <0, LaneLen, ... , LaneLen*(Factor - 1), 1, LaneLen + 1, ...>
|
/// I.e. <0, LaneLen, ... , LaneLen*(Factor - 1), 1, LaneLen + 1, ...>
|
||||||
/// E.g. For a Factor of 2 (LaneLen=4): <0, 4, 1, 5, 2, 6, 3, 7>
|
/// E.g. For a Factor of 2 (LaneLen=4): <0, 4, 1, 5, 2, 6, 3, 7>
|
||||||
static bool isReInterleaveMask(ArrayRef<int> Mask, unsigned &Factor,
|
static bool isReInterleaveMask(ArrayRef<int> Mask, unsigned &Factor,
|
||||||
unsigned MaxFactor) {
|
unsigned MaxFactor, unsigned OpNumElts) {
|
||||||
unsigned NumElts = Mask.size();
|
unsigned NumElts = Mask.size();
|
||||||
if (NumElts < 4)
|
if (NumElts < 4)
|
||||||
return false;
|
return false;
|
||||||
@ -246,6 +246,9 @@ static bool isReInterleaveMask(ArrayRef<int> Mask, unsigned &Factor,
|
|||||||
|
|
||||||
if (StartMask < 0)
|
if (StartMask < 0)
|
||||||
break;
|
break;
|
||||||
|
// We must stay within the vectors; This case can happen with undefs.
|
||||||
|
if (StartMask + LaneLen > OpNumElts*2)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Found an interleaved mask of current factor.
|
// Found an interleaved mask of current factor.
|
||||||
@ -406,7 +409,8 @@ bool InterleavedAccess::lowerInterleavedStore(
|
|||||||
|
|
||||||
// Check if the shufflevector is RE-interleave shuffle.
|
// Check if the shufflevector is RE-interleave shuffle.
|
||||||
unsigned Factor;
|
unsigned Factor;
|
||||||
if (!isReInterleaveMask(SVI->getShuffleMask(), Factor, MaxFactor))
|
unsigned OpNumElts = SVI->getOperand(0)->getType()->getVectorNumElements();
|
||||||
|
if (!isReInterleaveMask(SVI->getShuffleMask(), Factor, MaxFactor, OpNumElts))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
DEBUG(dbgs() << "IA: Found an interleaved store: " << *SI << "\n");
|
DEBUG(dbgs() << "IA: Found an interleaved store: " << *SI << "\n");
|
||||||
|
@ -2248,7 +2248,7 @@ GetVBR(uint64_t Val, const unsigned char *MatcherTable, unsigned &Idx) {
|
|||||||
/// to use the new results.
|
/// to use the new results.
|
||||||
void SelectionDAGISel::UpdateChains(
|
void SelectionDAGISel::UpdateChains(
|
||||||
SDNode *NodeToMatch, SDValue InputChain,
|
SDNode *NodeToMatch, SDValue InputChain,
|
||||||
const SmallVectorImpl<SDNode *> &ChainNodesMatched, bool isMorphNodeTo) {
|
SmallVectorImpl<SDNode *> &ChainNodesMatched, bool isMorphNodeTo) {
|
||||||
SmallVector<SDNode*, 4> NowDeadNodes;
|
SmallVector<SDNode*, 4> NowDeadNodes;
|
||||||
|
|
||||||
// Now that all the normal results are replaced, we replace the chain and
|
// Now that all the normal results are replaced, we replace the chain and
|
||||||
@ -2260,6 +2260,11 @@ void SelectionDAGISel::UpdateChains(
|
|||||||
// Replace all the chain results with the final chain we ended up with.
|
// Replace all the chain results with the final chain we ended up with.
|
||||||
for (unsigned i = 0, e = ChainNodesMatched.size(); i != e; ++i) {
|
for (unsigned i = 0, e = ChainNodesMatched.size(); i != e; ++i) {
|
||||||
SDNode *ChainNode = ChainNodesMatched[i];
|
SDNode *ChainNode = ChainNodesMatched[i];
|
||||||
|
// If ChainNode is null, it's because we replaced it on a previous
|
||||||
|
// iteration and we cleared it out of the map. Just skip it.
|
||||||
|
if (!ChainNode)
|
||||||
|
continue;
|
||||||
|
|
||||||
assert(ChainNode->getOpcode() != ISD::DELETED_NODE &&
|
assert(ChainNode->getOpcode() != ISD::DELETED_NODE &&
|
||||||
"Deleted node left in chain");
|
"Deleted node left in chain");
|
||||||
|
|
||||||
@ -2272,6 +2277,11 @@ void SelectionDAGISel::UpdateChains(
|
|||||||
if (ChainVal.getValueType() == MVT::Glue)
|
if (ChainVal.getValueType() == MVT::Glue)
|
||||||
ChainVal = ChainVal.getValue(ChainVal->getNumValues()-2);
|
ChainVal = ChainVal.getValue(ChainVal->getNumValues()-2);
|
||||||
assert(ChainVal.getValueType() == MVT::Other && "Not a chain?");
|
assert(ChainVal.getValueType() == MVT::Other && "Not a chain?");
|
||||||
|
SelectionDAG::DAGNodeDeletedListener NDL(
|
||||||
|
*CurDAG, [&](SDNode *N, SDNode *E) {
|
||||||
|
std::replace(ChainNodesMatched.begin(), ChainNodesMatched.end(), N,
|
||||||
|
static_cast<SDNode *>(nullptr));
|
||||||
|
});
|
||||||
CurDAG->ReplaceAllUsesOfValueWith(ChainVal, InputChain);
|
CurDAG->ReplaceAllUsesOfValueWith(ChainVal, InputChain);
|
||||||
|
|
||||||
// If the node became dead and we haven't already seen it, delete it.
|
// If the node became dead and we haven't already seen it, delete it.
|
||||||
|
@ -142,7 +142,8 @@ static bool canGoAfterDWARF(const MCSectionMachO &MSec) {
|
|||||||
if (SegName == "__TEXT" && SecName == "__eh_frame")
|
if (SegName == "__TEXT" && SecName == "__eh_frame")
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (SegName == "__DATA" && SecName == "__nl_symbol_ptr")
|
if (SegName == "__DATA" && (SecName == "__nl_symbol_ptr" ||
|
||||||
|
SecName == "__thread_ptr"))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
@ -413,6 +413,7 @@ class MipsAsmParser : public MCTargetAsmParser {
|
|||||||
Match_RequiresDifferentOperands,
|
Match_RequiresDifferentOperands,
|
||||||
Match_RequiresNoZeroRegister,
|
Match_RequiresNoZeroRegister,
|
||||||
Match_RequiresSameSrcAndDst,
|
Match_RequiresSameSrcAndDst,
|
||||||
|
Match_NoFCCRegisterForCurrentISA,
|
||||||
Match_NonZeroOperandForSync,
|
Match_NonZeroOperandForSync,
|
||||||
#define GET_OPERAND_DIAGNOSTIC_TYPES
|
#define GET_OPERAND_DIAGNOSTIC_TYPES
|
||||||
#include "MipsGenAsmMatcher.inc"
|
#include "MipsGenAsmMatcher.inc"
|
||||||
@ -1461,8 +1462,6 @@ class MipsOperand : public MCParsedAsmOperand {
|
|||||||
bool isFCCAsmReg() const {
|
bool isFCCAsmReg() const {
|
||||||
if (!(isRegIdx() && RegIdx.Kind & RegKind_FCC))
|
if (!(isRegIdx() && RegIdx.Kind & RegKind_FCC))
|
||||||
return false;
|
return false;
|
||||||
if (!AsmParser.hasEightFccRegisters())
|
|
||||||
return RegIdx.Index == 0;
|
|
||||||
return RegIdx.Index <= 7;
|
return RegIdx.Index <= 7;
|
||||||
}
|
}
|
||||||
bool isACCAsmReg() const {
|
bool isACCAsmReg() const {
|
||||||
@ -4053,6 +4052,7 @@ MipsAsmParser::checkEarlyTargetMatchPredicate(MCInst &Inst,
|
|||||||
return Match_RequiresSameSrcAndDst;
|
return Match_RequiresSameSrcAndDst;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned MipsAsmParser::checkTargetMatchPredicate(MCInst &Inst) {
|
unsigned MipsAsmParser::checkTargetMatchPredicate(MCInst &Inst) {
|
||||||
switch (Inst.getOpcode()) {
|
switch (Inst.getOpcode()) {
|
||||||
// As described by the MIPSR6 spec, daui must not use the zero operand for
|
// As described by the MIPSR6 spec, daui must not use the zero operand for
|
||||||
@ -4131,9 +4131,15 @@ unsigned MipsAsmParser::checkTargetMatchPredicate(MCInst &Inst) {
|
|||||||
if (Inst.getOperand(0).getReg() == Inst.getOperand(1).getReg())
|
if (Inst.getOperand(0).getReg() == Inst.getOperand(1).getReg())
|
||||||
return Match_RequiresDifferentOperands;
|
return Match_RequiresDifferentOperands;
|
||||||
return Match_Success;
|
return Match_Success;
|
||||||
default:
|
|
||||||
return Match_Success;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint64_t TSFlags = getInstDesc(Inst.getOpcode()).TSFlags;
|
||||||
|
if ((TSFlags & MipsII::HasFCCRegOperand) &&
|
||||||
|
(Inst.getOperand(0).getReg() != Mips::FCC0) && !hasEightFccRegisters())
|
||||||
|
return Match_NoFCCRegisterForCurrentISA;
|
||||||
|
|
||||||
|
return Match_Success;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static SMLoc RefineErrorLoc(const SMLoc Loc, const OperandVector &Operands,
|
static SMLoc RefineErrorLoc(const SMLoc Loc, const OperandVector &Operands,
|
||||||
@ -4191,6 +4197,9 @@ bool MipsAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
|
|||||||
return Error(IDLoc, "invalid operand ($zero) for instruction");
|
return Error(IDLoc, "invalid operand ($zero) for instruction");
|
||||||
case Match_RequiresSameSrcAndDst:
|
case Match_RequiresSameSrcAndDst:
|
||||||
return Error(IDLoc, "source and destination must match");
|
return Error(IDLoc, "source and destination must match");
|
||||||
|
case Match_NoFCCRegisterForCurrentISA:
|
||||||
|
return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo),
|
||||||
|
"non-zero fcc register doesn't exist in current ISA level");
|
||||||
case Match_Immz:
|
case Match_Immz:
|
||||||
return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), "expected '0'");
|
return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), "expected '0'");
|
||||||
case Match_UImm1_0:
|
case Match_UImm1_0:
|
||||||
|
@ -123,7 +123,9 @@ namespace MipsII {
|
|||||||
HasForbiddenSlot = 1 << 5,
|
HasForbiddenSlot = 1 << 5,
|
||||||
/// IsPCRelativeLoad - A Load instruction with implicit source register
|
/// IsPCRelativeLoad - A Load instruction with implicit source register
|
||||||
/// ($pc) with explicit offset and destination register
|
/// ($pc) with explicit offset and destination register
|
||||||
IsPCRelativeLoad = 1 << 6
|
IsPCRelativeLoad = 1 << 6,
|
||||||
|
/// HasFCCRegOperand - Instruction uses an $fcc<x> register.
|
||||||
|
HasFCCRegOperand = 1 << 7
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -27,9 +27,20 @@ def SUXC1_MM : MMRel, SWXC1_FT<"suxc1", AFGR64Opnd, II_SUXC1>,
|
|||||||
SWXC1_FM_MM<0x188>, INSN_MIPS5_32R2_NOT_32R6_64R6;
|
SWXC1_FM_MM<0x188>, INSN_MIPS5_32R2_NOT_32R6_64R6;
|
||||||
|
|
||||||
def FCMP_S32_MM : MMRel, CEQS_FT<"s", FGR32, II_C_CC_S, MipsFPCmp>,
|
def FCMP_S32_MM : MMRel, CEQS_FT<"s", FGR32, II_C_CC_S, MipsFPCmp>,
|
||||||
CEQS_FM_MM<0>;
|
CEQS_FM_MM<0> {
|
||||||
|
// FIXME: This is a required to work around the fact that these instructions
|
||||||
|
// only use $fcc0. Ideally, MipsFPCmp nodes could be removed and the
|
||||||
|
// fcc register set is used directly.
|
||||||
|
bits<3> fcc = 0;
|
||||||
|
}
|
||||||
|
|
||||||
def FCMP_D32_MM : MMRel, CEQS_FT<"d", AFGR64, II_C_CC_D, MipsFPCmp>,
|
def FCMP_D32_MM : MMRel, CEQS_FT<"d", AFGR64, II_C_CC_D, MipsFPCmp>,
|
||||||
CEQS_FM_MM<1>;
|
CEQS_FM_MM<1> {
|
||||||
|
// FIXME: This is a required to work around the fact that these instructions
|
||||||
|
// only use $fcc0. Ideally, MipsFPCmp nodes could be removed and the
|
||||||
|
// fcc register set is used directly.
|
||||||
|
bits<3> fcc = 0;
|
||||||
|
}
|
||||||
|
|
||||||
def BC1F_MM : MMRel, BC1F_FT<"bc1f", brtarget_mm, II_BC1F, MIPS_BRANCH_F>,
|
def BC1F_MM : MMRel, BC1F_FT<"bc1f", brtarget_mm, II_BC1F, MIPS_BRANCH_F>,
|
||||||
BC1F_FM_MM<0x1c>, ISA_MIPS1_NOT_32R6_64R6;
|
BC1F_FM_MM<0x1c>, ISA_MIPS1_NOT_32R6_64R6;
|
||||||
@ -164,6 +175,98 @@ let AdditionalPredicates = [InMicroMips] in {
|
|||||||
def SWC1_MM : MMRel, SW_FT<"swc1", FGR32Opnd, mem_mm_16, II_SWC1, store>,
|
def SWC1_MM : MMRel, SW_FT<"swc1", FGR32Opnd, mem_mm_16, II_SWC1, store>,
|
||||||
LW_FM_MM<0x26>;
|
LW_FM_MM<0x26>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
multiclass C_COND_MM<string TypeStr, RegisterOperand RC, bits<2> fmt,
|
||||||
|
InstrItinClass itin> {
|
||||||
|
def C_F_#NAME#_MM : MMRel, C_COND_FT<"f", TypeStr, RC, itin>,
|
||||||
|
C_COND_FM_MM<fmt, 0> {
|
||||||
|
let BaseOpcode = "c.f."#NAME;
|
||||||
|
let isCommutable = 1;
|
||||||
|
}
|
||||||
|
def C_UN_#NAME#_MM : MMRel, C_COND_FT<"un", TypeStr, RC, itin>,
|
||||||
|
C_COND_FM_MM<fmt, 1> {
|
||||||
|
let BaseOpcode = "c.un."#NAME;
|
||||||
|
let isCommutable = 1;
|
||||||
|
}
|
||||||
|
def C_EQ_#NAME#_MM : MMRel, C_COND_FT<"eq", TypeStr, RC, itin>,
|
||||||
|
C_COND_FM_MM<fmt, 2> {
|
||||||
|
let BaseOpcode = "c.eq."#NAME;
|
||||||
|
let isCommutable = 1;
|
||||||
|
}
|
||||||
|
def C_UEQ_#NAME#_MM : MMRel, C_COND_FT<"ueq", TypeStr, RC, itin>,
|
||||||
|
C_COND_FM_MM<fmt, 3> {
|
||||||
|
let BaseOpcode = "c.ueq."#NAME;
|
||||||
|
let isCommutable = 1;
|
||||||
|
}
|
||||||
|
def C_OLT_#NAME#_MM : MMRel, C_COND_FT<"olt", TypeStr, RC, itin>,
|
||||||
|
C_COND_FM_MM<fmt, 4> {
|
||||||
|
let BaseOpcode = "c.olt."#NAME;
|
||||||
|
}
|
||||||
|
def C_ULT_#NAME#_MM : MMRel, C_COND_FT<"ult", TypeStr, RC, itin>,
|
||||||
|
C_COND_FM_MM<fmt, 5> {
|
||||||
|
let BaseOpcode = "c.ult."#NAME;
|
||||||
|
}
|
||||||
|
def C_OLE_#NAME#_MM : MMRel, C_COND_FT<"ole", TypeStr, RC, itin>,
|
||||||
|
C_COND_FM_MM<fmt, 6> {
|
||||||
|
let BaseOpcode = "c.ole."#NAME;
|
||||||
|
}
|
||||||
|
def C_ULE_#NAME#_MM : MMRel, C_COND_FT<"ule", TypeStr, RC, itin>,
|
||||||
|
C_COND_FM_MM<fmt, 7> {
|
||||||
|
let BaseOpcode = "c.ule."#NAME;
|
||||||
|
}
|
||||||
|
def C_SF_#NAME#_MM : MMRel, C_COND_FT<"sf", TypeStr, RC, itin>,
|
||||||
|
C_COND_FM_MM<fmt, 8> {
|
||||||
|
let BaseOpcode = "c.sf."#NAME;
|
||||||
|
let isCommutable = 1;
|
||||||
|
}
|
||||||
|
def C_NGLE_#NAME#_MM : MMRel, C_COND_FT<"ngle", TypeStr, RC, itin>,
|
||||||
|
C_COND_FM_MM<fmt, 9> {
|
||||||
|
let BaseOpcode = "c.ngle."#NAME;
|
||||||
|
}
|
||||||
|
def C_SEQ_#NAME#_MM : MMRel, C_COND_FT<"seq", TypeStr, RC, itin>,
|
||||||
|
C_COND_FM_MM<fmt, 10> {
|
||||||
|
let BaseOpcode = "c.seq."#NAME;
|
||||||
|
let isCommutable = 1;
|
||||||
|
}
|
||||||
|
def C_NGL_#NAME#_MM : MMRel, C_COND_FT<"ngl", TypeStr, RC, itin>,
|
||||||
|
C_COND_FM_MM<fmt, 11> {
|
||||||
|
let BaseOpcode = "c.ngl."#NAME;
|
||||||
|
}
|
||||||
|
def C_LT_#NAME#_MM : MMRel, C_COND_FT<"lt", TypeStr, RC, itin>,
|
||||||
|
C_COND_FM_MM<fmt, 12> {
|
||||||
|
let BaseOpcode = "c.lt."#NAME;
|
||||||
|
}
|
||||||
|
def C_NGE_#NAME#_MM : MMRel, C_COND_FT<"nge", TypeStr, RC, itin>,
|
||||||
|
C_COND_FM_MM<fmt, 13> {
|
||||||
|
let BaseOpcode = "c.nge."#NAME;
|
||||||
|
}
|
||||||
|
def C_LE_#NAME#_MM : MMRel, C_COND_FT<"le", TypeStr, RC, itin>,
|
||||||
|
C_COND_FM_MM<fmt, 14> {
|
||||||
|
let BaseOpcode = "c.le."#NAME;
|
||||||
|
}
|
||||||
|
def C_NGT_#NAME#_MM : MMRel, C_COND_FT<"ngt", TypeStr, RC, itin>,
|
||||||
|
C_COND_FM_MM<fmt, 15> {
|
||||||
|
let BaseOpcode = "c.ngt."#NAME;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
defm S : C_COND_MM<"s", FGR32Opnd, 0b00, II_C_CC_S>,
|
||||||
|
ISA_MIPS1_NOT_32R6_64R6;
|
||||||
|
defm D32 : C_COND_MM<"d", AFGR64Opnd, 0b01, II_C_CC_D>,
|
||||||
|
ISA_MIPS1_NOT_32R6_64R6, FGR_32;
|
||||||
|
let DecoderNamespace = "Mips64" in
|
||||||
|
defm D64 : C_COND_MM<"d", FGR64Opnd, 0b01, II_C_CC_D>,
|
||||||
|
ISA_MIPS1_NOT_32R6_64R6, FGR_64;
|
||||||
|
|
||||||
|
defm S_MM : C_COND_ALIASES<"s", FGR32Opnd>, HARDFLOAT,
|
||||||
|
ISA_MIPS1_NOT_32R6_64R6;
|
||||||
|
defm D32_MM : C_COND_ALIASES<"d", AFGR64Opnd>, HARDFLOAT,
|
||||||
|
ISA_MIPS1_NOT_32R6_64R6, FGR_32;
|
||||||
|
defm D64_MM : C_COND_ALIASES<"d", FGR64Opnd>, HARDFLOAT,
|
||||||
|
ISA_MIPS1_NOT_32R6_64R6, FGR_64;
|
||||||
|
|
||||||
|
defm : BC1_ALIASES<BC1T_MM, "bc1t", BC1F_MM, "bc1f">,
|
||||||
|
ISA_MIPS1_NOT_32R6_64R6, HARDFLOAT;
|
||||||
}
|
}
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
@ -766,6 +766,7 @@ class SWXC1_FM_MM<bits<9> funct> : MMArch {
|
|||||||
class CEQS_FM_MM<bits<2> fmt> : MMArch {
|
class CEQS_FM_MM<bits<2> fmt> : MMArch {
|
||||||
bits<5> fs;
|
bits<5> fs;
|
||||||
bits<5> ft;
|
bits<5> ft;
|
||||||
|
bits<3> fcc;
|
||||||
bits<4> cond;
|
bits<4> cond;
|
||||||
|
|
||||||
bits<32> Inst;
|
bits<32> Inst;
|
||||||
@ -773,13 +774,17 @@ class CEQS_FM_MM<bits<2> fmt> : MMArch {
|
|||||||
let Inst{31-26} = 0x15;
|
let Inst{31-26} = 0x15;
|
||||||
let Inst{25-21} = ft;
|
let Inst{25-21} = ft;
|
||||||
let Inst{20-16} = fs;
|
let Inst{20-16} = fs;
|
||||||
let Inst{15-13} = 0x0; // cc
|
let Inst{15-13} = fcc;
|
||||||
let Inst{12} = 0;
|
let Inst{12} = 0;
|
||||||
let Inst{11-10} = fmt;
|
let Inst{11-10} = fmt;
|
||||||
let Inst{9-6} = cond;
|
let Inst{9-6} = cond;
|
||||||
let Inst{5-0} = 0x3c;
|
let Inst{5-0} = 0x3c;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class C_COND_FM_MM<bits <2> fmt, bits<4> c> : CEQS_FM_MM<fmt> {
|
||||||
|
let cond = c;
|
||||||
|
}
|
||||||
|
|
||||||
class BC1F_FM_MM<bits<5> tf> : MMArch {
|
class BC1F_FM_MM<bits<5> tf> : MMArch {
|
||||||
bits<16> offset;
|
bits<16> offset;
|
||||||
|
|
||||||
|
@ -1037,6 +1037,22 @@ void MipsAsmPrinter::PrintDebugValueComment(const MachineInstr *MI,
|
|||||||
// TODO: implement
|
// TODO: implement
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Emit .dtprelword or .dtpreldword directive
|
||||||
|
// and value for debug thread local expression.
|
||||||
|
void MipsAsmPrinter::EmitDebugValue(const MCExpr *Value,
|
||||||
|
unsigned Size) const {
|
||||||
|
switch (Size) {
|
||||||
|
case 4:
|
||||||
|
OutStreamer->EmitDTPRel32Value(Value);
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
OutStreamer->EmitDTPRel64Value(Value);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
llvm_unreachable("Unexpected size of expression value.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Align all targets of indirect branches on bundle size. Used only if target
|
// Align all targets of indirect branches on bundle size. Used only if target
|
||||||
// is NaCl.
|
// is NaCl.
|
||||||
void MipsAsmPrinter::NaClAlignIndirectJumpTargets(MachineFunction &MF) {
|
void MipsAsmPrinter::NaClAlignIndirectJumpTargets(MachineFunction &MF) {
|
||||||
|
@ -140,6 +140,7 @@ class LLVM_LIBRARY_VISIBILITY MipsAsmPrinter : public AsmPrinter {
|
|||||||
void EmitStartOfAsmFile(Module &M) override;
|
void EmitStartOfAsmFile(Module &M) override;
|
||||||
void EmitEndOfAsmFile(Module &M) override;
|
void EmitEndOfAsmFile(Module &M) override;
|
||||||
void PrintDebugValueComment(const MachineInstr *MI, raw_ostream &OS);
|
void PrintDebugValueComment(const MachineInstr *MI, raw_ostream &OS);
|
||||||
|
void EmitDebugValue(const MCExpr *Value, unsigned Size) const override;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -698,8 +698,8 @@ bool MipsFastISel::emitCmp(unsigned ResultReg, const CmpInst *CI) {
|
|||||||
unsigned RegWithOne = createResultReg(&Mips::GPR32RegClass);
|
unsigned RegWithOne = createResultReg(&Mips::GPR32RegClass);
|
||||||
emitInst(Mips::ADDiu, RegWithZero).addReg(Mips::ZERO).addImm(0);
|
emitInst(Mips::ADDiu, RegWithZero).addReg(Mips::ZERO).addImm(0);
|
||||||
emitInst(Mips::ADDiu, RegWithOne).addReg(Mips::ZERO).addImm(1);
|
emitInst(Mips::ADDiu, RegWithOne).addReg(Mips::ZERO).addImm(1);
|
||||||
emitInst(Opc).addReg(LeftReg).addReg(RightReg).addReg(
|
emitInst(Opc).addReg(Mips::FCC0, RegState::Define).addReg(LeftReg)
|
||||||
Mips::FCC0, RegState::ImplicitDefine);
|
.addReg(RightReg);
|
||||||
emitInst(CondMovOpc, ResultReg)
|
emitInst(CondMovOpc, ResultReg)
|
||||||
.addReg(RegWithOne)
|
.addReg(RegWithOne)
|
||||||
.addReg(Mips::FCC0)
|
.addReg(Mips::FCC0)
|
||||||
|
@ -219,6 +219,7 @@ class BC1F_FT<string opstr, DAGOperand opnd, InstrItinClass Itin,
|
|||||||
let isTerminator = 1;
|
let isTerminator = 1;
|
||||||
let hasDelaySlot = DelaySlot;
|
let hasDelaySlot = DelaySlot;
|
||||||
let Defs = [AT];
|
let Defs = [AT];
|
||||||
|
let hasFCCRegOperand = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
class CEQS_FT<string typestr, RegisterClass RC, InstrItinClass Itin,
|
class CEQS_FT<string typestr, RegisterClass RC, InstrItinClass Itin,
|
||||||
@ -229,41 +230,106 @@ class CEQS_FT<string typestr, RegisterClass RC, InstrItinClass Itin,
|
|||||||
!strconcat("c.$cond.", typestr)>, HARDFLOAT {
|
!strconcat("c.$cond.", typestr)>, HARDFLOAT {
|
||||||
let Defs = [FCC0];
|
let Defs = [FCC0];
|
||||||
let isCodeGenOnly = 1;
|
let isCodeGenOnly = 1;
|
||||||
|
let hasFCCRegOperand = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Note: MIPS-IV introduced $fcc1-$fcc7 and renamed FCSR31[23] $fcc0. Rather
|
||||||
|
// duplicating the instruction definition for MIPS1 - MIPS3, we expand
|
||||||
|
// c.cond.ft if necessary, and reject it after constructing the
|
||||||
|
// instruction if the ISA doesn't support it.
|
||||||
class C_COND_FT<string CondStr, string Typestr, RegisterOperand RC,
|
class C_COND_FT<string CondStr, string Typestr, RegisterOperand RC,
|
||||||
InstrItinClass itin> :
|
InstrItinClass itin> :
|
||||||
InstSE<(outs), (ins RC:$fs, RC:$ft),
|
InstSE<(outs FCCRegsOpnd:$fcc), (ins RC:$fs, RC:$ft),
|
||||||
!strconcat("c.", CondStr, ".", Typestr, "\t$fs, $ft"), [], itin,
|
!strconcat("c.", CondStr, ".", Typestr, "\t$fcc, $fs, $ft"), [], itin,
|
||||||
FrmFR>, HARDFLOAT;
|
FrmFR>, HARDFLOAT {
|
||||||
|
let isCompare = 1;
|
||||||
|
let hasFCCRegOperand = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
multiclass C_COND_M<string TypeStr, RegisterOperand RC, bits<5> fmt,
|
multiclass C_COND_M<string TypeStr, RegisterOperand RC, bits<5> fmt,
|
||||||
InstrItinClass itin> {
|
InstrItinClass itin> {
|
||||||
def C_F_#NAME : C_COND_FT<"f", TypeStr, RC, itin>, C_COND_FM<fmt, 0>;
|
def C_F_#NAME : MMRel, C_COND_FT<"f", TypeStr, RC, itin>,
|
||||||
def C_UN_#NAME : C_COND_FT<"un", TypeStr, RC, itin>, C_COND_FM<fmt, 1>;
|
C_COND_FM<fmt, 0> {
|
||||||
def C_EQ_#NAME : C_COND_FT<"eq", TypeStr, RC, itin>, C_COND_FM<fmt, 2>;
|
let BaseOpcode = "c.f."#NAME;
|
||||||
def C_UEQ_#NAME : C_COND_FT<"ueq", TypeStr, RC, itin>, C_COND_FM<fmt, 3>;
|
let isCommutable = 1;
|
||||||
def C_OLT_#NAME : C_COND_FT<"olt", TypeStr, RC, itin>, C_COND_FM<fmt, 4>;
|
}
|
||||||
def C_ULT_#NAME : C_COND_FT<"ult", TypeStr, RC, itin>, C_COND_FM<fmt, 5>;
|
def C_UN_#NAME : MMRel, C_COND_FT<"un", TypeStr, RC, itin>,
|
||||||
def C_OLE_#NAME : C_COND_FT<"ole", TypeStr, RC, itin>, C_COND_FM<fmt, 6>;
|
C_COND_FM<fmt, 1> {
|
||||||
def C_ULE_#NAME : C_COND_FT<"ule", TypeStr, RC, itin>, C_COND_FM<fmt, 7>;
|
let BaseOpcode = "c.un."#NAME;
|
||||||
def C_SF_#NAME : C_COND_FT<"sf", TypeStr, RC, itin>, C_COND_FM<fmt, 8>;
|
let isCommutable = 1;
|
||||||
def C_NGLE_#NAME : C_COND_FT<"ngle", TypeStr, RC, itin>, C_COND_FM<fmt, 9>;
|
}
|
||||||
def C_SEQ_#NAME : C_COND_FT<"seq", TypeStr, RC, itin>, C_COND_FM<fmt, 10>;
|
def C_EQ_#NAME : MMRel, C_COND_FT<"eq", TypeStr, RC, itin>,
|
||||||
def C_NGL_#NAME : C_COND_FT<"ngl", TypeStr, RC, itin>, C_COND_FM<fmt, 11>;
|
C_COND_FM<fmt, 2> {
|
||||||
def C_LT_#NAME : C_COND_FT<"lt", TypeStr, RC, itin>, C_COND_FM<fmt, 12>;
|
let BaseOpcode = "c.eq."#NAME;
|
||||||
def C_NGE_#NAME : C_COND_FT<"nge", TypeStr, RC, itin>, C_COND_FM<fmt, 13>;
|
let isCommutable = 1;
|
||||||
def C_LE_#NAME : C_COND_FT<"le", TypeStr, RC, itin>, C_COND_FM<fmt, 14>;
|
}
|
||||||
def C_NGT_#NAME : C_COND_FT<"ngt", TypeStr, RC, itin>, C_COND_FM<fmt, 15>;
|
def C_UEQ_#NAME : MMRel, C_COND_FT<"ueq", TypeStr, RC, itin>,
|
||||||
|
C_COND_FM<fmt, 3> {
|
||||||
|
let BaseOpcode = "c.ueq."#NAME;
|
||||||
|
let isCommutable = 1;
|
||||||
|
}
|
||||||
|
def C_OLT_#NAME : MMRel, C_COND_FT<"olt", TypeStr, RC, itin>,
|
||||||
|
C_COND_FM<fmt, 4> {
|
||||||
|
let BaseOpcode = "c.olt."#NAME;
|
||||||
|
}
|
||||||
|
def C_ULT_#NAME : MMRel, C_COND_FT<"ult", TypeStr, RC, itin>,
|
||||||
|
C_COND_FM<fmt, 5> {
|
||||||
|
let BaseOpcode = "c.ult."#NAME;
|
||||||
|
}
|
||||||
|
def C_OLE_#NAME : MMRel, C_COND_FT<"ole", TypeStr, RC, itin>,
|
||||||
|
C_COND_FM<fmt, 6> {
|
||||||
|
let BaseOpcode = "c.ole."#NAME;
|
||||||
|
}
|
||||||
|
def C_ULE_#NAME : MMRel, C_COND_FT<"ule", TypeStr, RC, itin>,
|
||||||
|
C_COND_FM<fmt, 7> {
|
||||||
|
let BaseOpcode = "c.ule."#NAME;
|
||||||
|
}
|
||||||
|
def C_SF_#NAME : MMRel, C_COND_FT<"sf", TypeStr, RC, itin>,
|
||||||
|
C_COND_FM<fmt, 8> {
|
||||||
|
let BaseOpcode = "c.sf."#NAME;
|
||||||
|
let isCommutable = 1;
|
||||||
|
}
|
||||||
|
def C_NGLE_#NAME : MMRel, C_COND_FT<"ngle", TypeStr, RC, itin>,
|
||||||
|
C_COND_FM<fmt, 9> {
|
||||||
|
let BaseOpcode = "c.ngle."#NAME;
|
||||||
|
}
|
||||||
|
def C_SEQ_#NAME : MMRel, C_COND_FT<"seq", TypeStr, RC, itin>,
|
||||||
|
C_COND_FM<fmt, 10> {
|
||||||
|
let BaseOpcode = "c.seq."#NAME;
|
||||||
|
let isCommutable = 1;
|
||||||
|
}
|
||||||
|
def C_NGL_#NAME : MMRel, C_COND_FT<"ngl", TypeStr, RC, itin>,
|
||||||
|
C_COND_FM<fmt, 11> {
|
||||||
|
let BaseOpcode = "c.ngl."#NAME;
|
||||||
|
}
|
||||||
|
def C_LT_#NAME : MMRel, C_COND_FT<"lt", TypeStr, RC, itin>,
|
||||||
|
C_COND_FM<fmt, 12> {
|
||||||
|
let BaseOpcode = "c.lt."#NAME;
|
||||||
|
}
|
||||||
|
def C_NGE_#NAME : MMRel, C_COND_FT<"nge", TypeStr, RC, itin>,
|
||||||
|
C_COND_FM<fmt, 13> {
|
||||||
|
let BaseOpcode = "c.nge."#NAME;
|
||||||
|
}
|
||||||
|
def C_LE_#NAME : MMRel, C_COND_FT<"le", TypeStr, RC, itin>,
|
||||||
|
C_COND_FM<fmt, 14> {
|
||||||
|
let BaseOpcode = "c.le."#NAME;
|
||||||
|
}
|
||||||
|
def C_NGT_#NAME : MMRel, C_COND_FT<"ngt", TypeStr, RC, itin>,
|
||||||
|
C_COND_FM<fmt, 15> {
|
||||||
|
let BaseOpcode = "c.ngt."#NAME;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let AdditionalPredicates = [NotInMicroMips] in {
|
||||||
defm S : C_COND_M<"s", FGR32Opnd, 16, II_C_CC_S>, ISA_MIPS1_NOT_32R6_64R6;
|
defm S : C_COND_M<"s", FGR32Opnd, 16, II_C_CC_S>, ISA_MIPS1_NOT_32R6_64R6;
|
||||||
defm D32 : C_COND_M<"d", AFGR64Opnd, 17, II_C_CC_D>, ISA_MIPS1_NOT_32R6_64R6,
|
defm D32 : C_COND_M<"d", AFGR64Opnd, 17, II_C_CC_D>, ISA_MIPS1_NOT_32R6_64R6,
|
||||||
FGR_32;
|
FGR_32;
|
||||||
let DecoderNamespace = "Mips64" in
|
let DecoderNamespace = "Mips64" in
|
||||||
defm D64 : C_COND_M<"d", FGR64Opnd, 17, II_C_CC_D>, ISA_MIPS1_NOT_32R6_64R6,
|
defm D64 : C_COND_M<"d", FGR64Opnd, 17, II_C_CC_D>, ISA_MIPS1_NOT_32R6_64R6,
|
||||||
FGR_64;
|
FGR_64;
|
||||||
|
}
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
// Floating Point Instructions
|
// Floating Point Instructions
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
@ -549,13 +615,29 @@ def BC1TL : MMRel, BC1F_FT<"bc1tl", brtarget, II_BC1TL, MIPS_BRANCH_T, 0>,
|
|||||||
/// Floating Point Compare
|
/// Floating Point Compare
|
||||||
let AdditionalPredicates = [NotInMicroMips] in {
|
let AdditionalPredicates = [NotInMicroMips] in {
|
||||||
def FCMP_S32 : MMRel, CEQS_FT<"s", FGR32, II_C_CC_S, MipsFPCmp>, CEQS_FM<16>,
|
def FCMP_S32 : MMRel, CEQS_FT<"s", FGR32, II_C_CC_S, MipsFPCmp>, CEQS_FM<16>,
|
||||||
ISA_MIPS1_NOT_32R6_64R6;
|
ISA_MIPS1_NOT_32R6_64R6 {
|
||||||
|
|
||||||
|
// FIXME: This is a required to work around the fact that these instructions
|
||||||
|
// only use $fcc0. Ideally, MipsFPCmp nodes could be removed and the
|
||||||
|
// fcc register set is used directly.
|
||||||
|
bits<3> fcc = 0;
|
||||||
|
}
|
||||||
def FCMP_D32 : MMRel, CEQS_FT<"d", AFGR64, II_C_CC_D, MipsFPCmp>, CEQS_FM<17>,
|
def FCMP_D32 : MMRel, CEQS_FT<"d", AFGR64, II_C_CC_D, MipsFPCmp>, CEQS_FM<17>,
|
||||||
ISA_MIPS1_NOT_32R6_64R6, FGR_32;
|
ISA_MIPS1_NOT_32R6_64R6, FGR_32 {
|
||||||
|
// FIXME: This is a required to work around the fact that these instructions
|
||||||
|
// only use $fcc0. Ideally, MipsFPCmp nodes could be removed and the
|
||||||
|
// fcc register set is used directly.
|
||||||
|
bits<3> fcc = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
let DecoderNamespace = "Mips64" in
|
let DecoderNamespace = "Mips64" in
|
||||||
def FCMP_D64 : CEQS_FT<"d", FGR64, II_C_CC_D, MipsFPCmp>, CEQS_FM<17>,
|
def FCMP_D64 : CEQS_FT<"d", FGR64, II_C_CC_D, MipsFPCmp>, CEQS_FM<17>,
|
||||||
ISA_MIPS1_NOT_32R6_64R6, FGR_64;
|
ISA_MIPS1_NOT_32R6_64R6, FGR_64 {
|
||||||
|
// FIXME: This is a required to work around the fact that thiese instructions
|
||||||
|
// only use $fcc0. Ideally, MipsFPCmp nodes could be removed and the
|
||||||
|
// fcc register set is used directly.
|
||||||
|
bits<3> fcc = 0;
|
||||||
|
}
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
// Floating Point Pseudo-Instructions
|
// Floating Point Pseudo-Instructions
|
||||||
@ -602,15 +684,6 @@ def PseudoTRUNC_W_D : MipsAsmPseudoInst<(outs FGR32Opnd:$fd),
|
|||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
// InstAliases.
|
// InstAliases.
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
def : MipsInstAlias<"bc1t $offset", (BC1T FCC0, brtarget:$offset)>,
|
|
||||||
ISA_MIPS1_NOT_32R6_64R6, HARDFLOAT;
|
|
||||||
def : MipsInstAlias<"bc1tl $offset", (BC1TL FCC0, brtarget:$offset)>,
|
|
||||||
ISA_MIPS2_NOT_32R6_64R6, HARDFLOAT;
|
|
||||||
def : MipsInstAlias<"bc1f $offset", (BC1F FCC0, brtarget:$offset)>,
|
|
||||||
ISA_MIPS1_NOT_32R6_64R6, HARDFLOAT;
|
|
||||||
def : MipsInstAlias<"bc1fl $offset", (BC1FL FCC0, brtarget:$offset)>,
|
|
||||||
ISA_MIPS2_NOT_32R6_64R6, HARDFLOAT;
|
|
||||||
|
|
||||||
def : MipsInstAlias
|
def : MipsInstAlias
|
||||||
<"s.s $fd, $addr", (SWC1 FGR32Opnd:$fd, mem_simm16:$addr), 0>,
|
<"s.s $fd, $addr", (SWC1 FGR32Opnd:$fd, mem_simm16:$addr), 0>,
|
||||||
ISA_MIPS2, HARDFLOAT;
|
ISA_MIPS2, HARDFLOAT;
|
||||||
@ -630,6 +703,80 @@ def : MipsInstAlias
|
|||||||
def : MipsInstAlias
|
def : MipsInstAlias
|
||||||
<"l.d $fd, $addr", (LDC164 FGR64Opnd:$fd, mem_simm16:$addr), 0>,
|
<"l.d $fd, $addr", (LDC164 FGR64Opnd:$fd, mem_simm16:$addr), 0>,
|
||||||
FGR_64, ISA_MIPS2, HARDFLOAT;
|
FGR_64, ISA_MIPS2, HARDFLOAT;
|
||||||
|
|
||||||
|
multiclass C_COND_ALIASES<string TypeStr, RegisterOperand RC> {
|
||||||
|
def : MipsInstAlias<!strconcat("c.f.", TypeStr, " $fs, $ft"),
|
||||||
|
(!cast<Instruction>("C_F_"#NAME) FCC0,
|
||||||
|
RC:$fs, RC:$ft), 1>;
|
||||||
|
def : MipsInstAlias<!strconcat("c.un.", TypeStr, " $fs, $ft"),
|
||||||
|
(!cast<Instruction>("C_UN_"#NAME) FCC0,
|
||||||
|
RC:$fs, RC:$ft), 1>;
|
||||||
|
def : MipsInstAlias<!strconcat("c.eq.", TypeStr, " $fs, $ft"),
|
||||||
|
(!cast<Instruction>("C_EQ_"#NAME) FCC0,
|
||||||
|
RC:$fs, RC:$ft), 1>;
|
||||||
|
def : MipsInstAlias<!strconcat("c.ueq.", TypeStr, " $fs, $ft"),
|
||||||
|
(!cast<Instruction>("C_UEQ_"#NAME) FCC0,
|
||||||
|
RC:$fs, RC:$ft), 1>;
|
||||||
|
def : MipsInstAlias<!strconcat("c.olt.", TypeStr, " $fs, $ft"),
|
||||||
|
(!cast<Instruction>("C_OLT_"#NAME) FCC0,
|
||||||
|
RC:$fs, RC:$ft), 1>;
|
||||||
|
def : MipsInstAlias<!strconcat("c.ult.", TypeStr, " $fs, $ft"),
|
||||||
|
(!cast<Instruction>("C_ULT_"#NAME) FCC0,
|
||||||
|
RC:$fs, RC:$ft), 1>;
|
||||||
|
def : MipsInstAlias<!strconcat("c.ole.", TypeStr, " $fs, $ft"),
|
||||||
|
(!cast<Instruction>("C_OLE_"#NAME) FCC0,
|
||||||
|
RC:$fs, RC:$ft), 1>;
|
||||||
|
def : MipsInstAlias<!strconcat("c.ule.", TypeStr, " $fs, $ft"),
|
||||||
|
(!cast<Instruction>("C_ULE_"#NAME) FCC0,
|
||||||
|
RC:$fs, RC:$ft), 1>;
|
||||||
|
def : MipsInstAlias<!strconcat("c.sf.", TypeStr, " $fs, $ft"),
|
||||||
|
(!cast<Instruction>("C_SF_"#NAME) FCC0,
|
||||||
|
RC:$fs, RC:$ft), 1>;
|
||||||
|
def : MipsInstAlias<!strconcat("c.ngle.", TypeStr, " $fs, $ft"),
|
||||||
|
(!cast<Instruction>("C_NGLE_"#NAME) FCC0,
|
||||||
|
RC:$fs, RC:$ft), 1>;
|
||||||
|
def : MipsInstAlias<!strconcat("c.seq.", TypeStr, " $fs, $ft"),
|
||||||
|
(!cast<Instruction>("C_SEQ_"#NAME) FCC0,
|
||||||
|
RC:$fs, RC:$ft), 1>;
|
||||||
|
def : MipsInstAlias<!strconcat("c.ngl.", TypeStr, " $fs, $ft"),
|
||||||
|
(!cast<Instruction>("C_NGL_"#NAME) FCC0,
|
||||||
|
RC:$fs, RC:$ft), 1>;
|
||||||
|
def : MipsInstAlias<!strconcat("c.lt.", TypeStr, " $fs, $ft"),
|
||||||
|
(!cast<Instruction>("C_LT_"#NAME) FCC0,
|
||||||
|
RC:$fs, RC:$ft), 1>;
|
||||||
|
def : MipsInstAlias<!strconcat("c.nge.", TypeStr, " $fs, $ft"),
|
||||||
|
(!cast<Instruction>("C_NGE_"#NAME) FCC0,
|
||||||
|
RC:$fs, RC:$ft), 1>;
|
||||||
|
def : MipsInstAlias<!strconcat("c.le.", TypeStr, " $fs, $ft"),
|
||||||
|
(!cast<Instruction>("C_LE_"#NAME) FCC0,
|
||||||
|
RC:$fs, RC:$ft), 1>;
|
||||||
|
def : MipsInstAlias<!strconcat("c.ngt.", TypeStr, " $fs, $ft"),
|
||||||
|
(!cast<Instruction>("C_NGT_"#NAME) FCC0,
|
||||||
|
RC:$fs, RC:$ft), 1>;
|
||||||
|
}
|
||||||
|
|
||||||
|
multiclass BC1_ALIASES<Instruction BCTrue, string BCTrueString,
|
||||||
|
Instruction BCFalse, string BCFalseString> {
|
||||||
|
def : MipsInstAlias<!strconcat(BCTrueString, " $offset"),
|
||||||
|
(BCTrue FCC0, brtarget:$offset), 1>;
|
||||||
|
|
||||||
|
def : MipsInstAlias<!strconcat(BCFalseString, " $offset"),
|
||||||
|
(BCFalse FCC0, brtarget:$offset), 1>;
|
||||||
|
}
|
||||||
|
|
||||||
|
let AdditionalPredicates = [NotInMicroMips] in {
|
||||||
|
defm S : C_COND_ALIASES<"s", FGR32Opnd>, HARDFLOAT,
|
||||||
|
ISA_MIPS1_NOT_32R6_64R6;
|
||||||
|
defm D32 : C_COND_ALIASES<"d", AFGR64Opnd>, HARDFLOAT,
|
||||||
|
ISA_MIPS1_NOT_32R6_64R6, FGR_32;
|
||||||
|
defm D64 : C_COND_ALIASES<"d", FGR64Opnd>, HARDFLOAT,
|
||||||
|
ISA_MIPS1_NOT_32R6_64R6, FGR_64;
|
||||||
|
|
||||||
|
defm : BC1_ALIASES<BC1T, "bc1t", BC1F, "bc1f">, ISA_MIPS1_NOT_32R6_64R6,
|
||||||
|
HARDFLOAT;
|
||||||
|
defm : BC1_ALIASES<BC1TL, "bc1tl", BC1FL, "bc1fl">, ISA_MIPS2_NOT_32R6_64R6,
|
||||||
|
HARDFLOAT;
|
||||||
|
}
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
// Floating Point Patterns
|
// Floating Point Patterns
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
@ -101,12 +101,15 @@ class MipsInst<dag outs, dag ins, string asmstr, list<dag> pattern,
|
|||||||
bit IsPCRelativeLoad = 0; // Load instruction with implicit source register
|
bit IsPCRelativeLoad = 0; // Load instruction with implicit source register
|
||||||
// ($pc) and with explicit offset and destination
|
// ($pc) and with explicit offset and destination
|
||||||
// register
|
// register
|
||||||
|
bit hasFCCRegOperand = 0; // Instruction uses $fcc<X> register and is
|
||||||
|
// present in MIPS-I to MIPS-III.
|
||||||
|
|
||||||
// TSFlags layout should be kept in sync with MipsInstrInfo.h.
|
// TSFlags layout should be kept in sync with MCTargetDesc/MipsBaseInfo.h.
|
||||||
let TSFlags{3-0} = FormBits;
|
let TSFlags{3-0} = FormBits;
|
||||||
let TSFlags{4} = isCTI;
|
let TSFlags{4} = isCTI;
|
||||||
let TSFlags{5} = hasForbiddenSlot;
|
let TSFlags{5} = hasForbiddenSlot;
|
||||||
let TSFlags{6} = IsPCRelativeLoad;
|
let TSFlags{6} = IsPCRelativeLoad;
|
||||||
|
let TSFlags{7} = hasFCCRegOperand;
|
||||||
|
|
||||||
let DecoderNamespace = "Mips";
|
let DecoderNamespace = "Mips";
|
||||||
|
|
||||||
@ -829,6 +832,7 @@ class BC1F_FM<bit nd, bit tf> : StdArch {
|
|||||||
class CEQS_FM<bits<5> fmt> : StdArch {
|
class CEQS_FM<bits<5> fmt> : StdArch {
|
||||||
bits<5> fs;
|
bits<5> fs;
|
||||||
bits<5> ft;
|
bits<5> ft;
|
||||||
|
bits<3> fcc;
|
||||||
bits<4> cond;
|
bits<4> cond;
|
||||||
|
|
||||||
bits<32> Inst;
|
bits<32> Inst;
|
||||||
@ -837,7 +841,7 @@ class CEQS_FM<bits<5> fmt> : StdArch {
|
|||||||
let Inst{25-21} = fmt;
|
let Inst{25-21} = fmt;
|
||||||
let Inst{20-16} = ft;
|
let Inst{20-16} = ft;
|
||||||
let Inst{15-11} = fs;
|
let Inst{15-11} = fs;
|
||||||
let Inst{10-8} = 0; // cc
|
let Inst{10-8} = fcc;
|
||||||
let Inst{7-4} = 0x3;
|
let Inst{7-4} = 0x3;
|
||||||
let Inst{3-0} = cond;
|
let Inst{3-0} = cond;
|
||||||
}
|
}
|
||||||
|
@ -148,3 +148,11 @@ MCSection *MipsTargetObjectFile::getSectionForConstant(const DataLayout &DL,
|
|||||||
// Otherwise, we work the same as ELF.
|
// Otherwise, we work the same as ELF.
|
||||||
return TargetLoweringObjectFileELF::getSectionForConstant(DL, Kind, C, Align);
|
return TargetLoweringObjectFileELF::getSectionForConstant(DL, Kind, C, Align);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const MCExpr *
|
||||||
|
MipsTargetObjectFile::getDebugThreadLocalSymbol(const MCSymbol *Sym) const {
|
||||||
|
const MCExpr *Expr =
|
||||||
|
MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, getContext());
|
||||||
|
return MCBinaryExpr::createAdd(
|
||||||
|
Expr, MCConstantExpr::create(0x8000, getContext()), getContext());
|
||||||
|
}
|
||||||
|
@ -42,6 +42,8 @@ class MipsTargetMachine;
|
|||||||
MCSection *getSectionForConstant(const DataLayout &DL, SectionKind Kind,
|
MCSection *getSectionForConstant(const DataLayout &DL, SectionKind Kind,
|
||||||
const Constant *C,
|
const Constant *C,
|
||||||
unsigned &Align) const override;
|
unsigned &Align) const override;
|
||||||
|
/// Describe a TLS variable address within debug info.
|
||||||
|
const MCExpr *getDebugThreadLocalSymbol(const MCSymbol *Sym) const override;
|
||||||
};
|
};
|
||||||
} // end namespace llvm
|
} // end namespace llvm
|
||||||
|
|
||||||
|
@ -1508,8 +1508,14 @@ def DCBTST : DCB_Form_hint<246, (outs), (ins u5imm:$TH, memrr:$dst),
|
|||||||
PPC970_DGroup_Single;
|
PPC970_DGroup_Single;
|
||||||
} // hasSideEffects = 0
|
} // hasSideEffects = 0
|
||||||
|
|
||||||
|
def ICBLC : XForm_icbt<31, 230, (outs), (ins u4imm:$CT, memrr:$src),
|
||||||
|
"icblc $CT, $src", IIC_LdStStore>, Requires<[HasICBT]>;
|
||||||
|
def ICBLQ : XForm_icbt<31, 198, (outs), (ins u4imm:$CT, memrr:$src),
|
||||||
|
"icblq. $CT, $src", IIC_LdStLoad>, Requires<[HasICBT]>;
|
||||||
def ICBT : XForm_icbt<31, 22, (outs), (ins u4imm:$CT, memrr:$src),
|
def ICBT : XForm_icbt<31, 22, (outs), (ins u4imm:$CT, memrr:$src),
|
||||||
"icbt $CT, $src", IIC_LdStLoad>, Requires<[HasICBT]>;
|
"icbt $CT, $src", IIC_LdStLoad>, Requires<[HasICBT]>;
|
||||||
|
def ICBTLS : XForm_icbt<31, 486, (outs), (ins u4imm:$CT, memrr:$src),
|
||||||
|
"icbtls $CT, $src", IIC_LdStLoad>, Requires<[HasICBT]>;
|
||||||
|
|
||||||
def : Pat<(int_ppc_dcbt xoaddr:$dst),
|
def : Pat<(int_ppc_dcbt xoaddr:$dst),
|
||||||
(DCBT 0, xoaddr:$dst)>;
|
(DCBT 0, xoaddr:$dst)>;
|
||||||
@ -2381,6 +2387,13 @@ def MTSPR : XFXForm_1<31, 467, (outs), (ins i32imm:$SPR, gprc:$RT),
|
|||||||
def MFTB : XFXForm_1<31, 371, (outs gprc:$RT), (ins i32imm:$SPR),
|
def MFTB : XFXForm_1<31, 371, (outs gprc:$RT), (ins i32imm:$SPR),
|
||||||
"mftb $RT, $SPR", IIC_SprMFTB>;
|
"mftb $RT, $SPR", IIC_SprMFTB>;
|
||||||
|
|
||||||
|
def MFPMR : XFXForm_1<31, 334, (outs gprc:$RT), (ins i32imm:$SPR),
|
||||||
|
"mfpmr $RT, $SPR", IIC_SprMFPMR>;
|
||||||
|
|
||||||
|
def MTPMR : XFXForm_1<31, 462, (outs), (ins i32imm:$SPR, gprc:$RT),
|
||||||
|
"mtpmr $SPR, $RT", IIC_SprMTPMR>;
|
||||||
|
|
||||||
|
|
||||||
// A pseudo-instruction used to implement the read of the 64-bit cycle counter
|
// A pseudo-instruction used to implement the read of the 64-bit cycle counter
|
||||||
// on a 32-bit target.
|
// on a 32-bit target.
|
||||||
let hasSideEffects = 1, usesCustomInserter = 1 in
|
let hasSideEffects = 1, usesCustomInserter = 1 in
|
||||||
|
@ -118,6 +118,8 @@ def IIC_SprTLBIE : InstrItinClass;
|
|||||||
def IIC_SprABORT : InstrItinClass;
|
def IIC_SprABORT : InstrItinClass;
|
||||||
def IIC_SprMSGSYNC : InstrItinClass;
|
def IIC_SprMSGSYNC : InstrItinClass;
|
||||||
def IIC_SprSTOP : InstrItinClass;
|
def IIC_SprSTOP : InstrItinClass;
|
||||||
|
def IIC_SprMFPMR : InstrItinClass;
|
||||||
|
def IIC_SprMTPMR : InstrItinClass;
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
// Processor instruction itineraries.
|
// Processor instruction itineraries.
|
||||||
|
@ -249,6 +249,10 @@ def PPCE500mcItineraries : ProcessorItineraries<
|
|||||||
InstrStage<5, [E500_SFX0]>],
|
InstrStage<5, [E500_SFX0]>],
|
||||||
[8, 1],
|
[8, 1],
|
||||||
[E500_GPR_Bypass, E500_CR_Bypass]>,
|
[E500_GPR_Bypass, E500_CR_Bypass]>,
|
||||||
|
InstrItinData<IIC_SprMFPMR, [InstrStage<1, [E500_DIS0, E500_DIS1], 0>,
|
||||||
|
InstrStage<4, [E500_SFX0]>],
|
||||||
|
[7, 1], // Latency = 4, Repeat rate = 4
|
||||||
|
[E500_GPR_Bypass, E500_GPR_Bypass]>,
|
||||||
InstrItinData<IIC_SprMFMSR, [InstrStage<1, [E500_DIS0, E500_DIS1], 0>,
|
InstrItinData<IIC_SprMFMSR, [InstrStage<1, [E500_DIS0, E500_DIS1], 0>,
|
||||||
InstrStage<4, [E500_SFX0]>],
|
InstrStage<4, [E500_SFX0]>],
|
||||||
[7, 1], // Latency = 4, Repeat rate = 4
|
[7, 1], // Latency = 4, Repeat rate = 4
|
||||||
@ -257,6 +261,10 @@ def PPCE500mcItineraries : ProcessorItineraries<
|
|||||||
InstrStage<1, [E500_SFX0, E500_SFX1]>],
|
InstrStage<1, [E500_SFX0, E500_SFX1]>],
|
||||||
[4, 1], // Latency = 1, Repeat rate = 1
|
[4, 1], // Latency = 1, Repeat rate = 1
|
||||||
[E500_GPR_Bypass, E500_CR_Bypass]>,
|
[E500_GPR_Bypass, E500_CR_Bypass]>,
|
||||||
|
InstrItinData<IIC_SprMTPMR, [InstrStage<1, [E500_DIS0, E500_DIS1], 0>,
|
||||||
|
InstrStage<1, [E500_SFX0]>],
|
||||||
|
[4, 1], // Latency = 1, Repeat rate = 1
|
||||||
|
[E500_CR_Bypass, E500_GPR_Bypass]>,
|
||||||
InstrItinData<IIC_SprMFTB, [InstrStage<1, [E500_DIS0, E500_DIS1], 0>,
|
InstrItinData<IIC_SprMFTB, [InstrStage<1, [E500_DIS0, E500_DIS1], 0>,
|
||||||
InstrStage<4, [E500_SFX0]>],
|
InstrStage<4, [E500_SFX0]>],
|
||||||
[7, 1], // Latency = 4, Repeat rate = 4
|
[7, 1], // Latency = 4, Repeat rate = 4
|
||||||
|
@ -313,20 +313,24 @@ def PPCE5500Itineraries : ProcessorItineraries<
|
|||||||
InstrStage<5, [E5500_CFX_0]>],
|
InstrStage<5, [E5500_CFX_0]>],
|
||||||
[9, 2], // Latency = 5, Repeat rate = 5
|
[9, 2], // Latency = 5, Repeat rate = 5
|
||||||
[E5500_GPR_Bypass, E5500_CR_Bypass]>,
|
[E5500_GPR_Bypass, E5500_CR_Bypass]>,
|
||||||
InstrItinData<IIC_SprMFMSR, [InstrStage<1, [E5500_DIS0, E5500_DIS1], 0>,
|
InstrItinData<IIC_SprMFPMR, [InstrStage<1, [E5500_DIS0, E5500_DIS1], 0>,
|
||||||
InstrStage<4, [E5500_SFX0]>],
|
InstrStage<4, [E5500_CFX_0]>],
|
||||||
[8, 2], // Latency = 4, Repeat rate = 4
|
[8, 2], // Latency = 4, Repeat rate = 4
|
||||||
[E5500_GPR_Bypass, E5500_GPR_Bypass]>,
|
[E5500_GPR_Bypass, E5500_GPR_Bypass]>,
|
||||||
InstrItinData<IIC_SprMFSPR, [InstrStage<1, [E5500_DIS0, E5500_DIS1], 0>,
|
InstrItinData<IIC_SprMFSPR, [InstrStage<1, [E5500_DIS0, E5500_DIS1], 0>,
|
||||||
InstrStage<1, [E5500_CFX_0]>],
|
InstrStage<1, [E5500_CFX_0]>],
|
||||||
[5], // Latency = 1, Repeat rate = 1
|
[5], // Latency = 1, Repeat rate = 1
|
||||||
[E5500_GPR_Bypass]>,
|
[E5500_GPR_Bypass]>,
|
||||||
|
InstrItinData<IIC_SprMTPMR, [InstrStage<1, [E5500_DIS0, E5500_DIS1], 0>,
|
||||||
|
InstrStage<1, [E5500_CFX_0]>],
|
||||||
|
[5], // Latency = 1, Repeat rate = 1
|
||||||
|
[E5500_GPR_Bypass]>,
|
||||||
InstrItinData<IIC_SprMFTB, [InstrStage<1, [E5500_DIS0, E5500_DIS1], 0>,
|
InstrItinData<IIC_SprMFTB, [InstrStage<1, [E5500_DIS0, E5500_DIS1], 0>,
|
||||||
InstrStage<4, [E5500_CFX_0]>],
|
InstrStage<4, [E5500_CFX_0]>],
|
||||||
[8, 2], // Latency = 4, Repeat rate = 4
|
[8, 2], // Latency = 4, Repeat rate = 4
|
||||||
[NoBypass, E5500_GPR_Bypass]>,
|
[NoBypass, E5500_GPR_Bypass]>,
|
||||||
InstrItinData<IIC_SprMTSPR, [InstrStage<1, [E5500_DIS0, E5500_DIS1], 0>,
|
InstrItinData<IIC_SprMTSPR, [InstrStage<1, [E5500_DIS0, E5500_DIS1], 0>,
|
||||||
InstrStage<1, [E5500_SFX0, E5500_SFX1]>],
|
InstrStage<1, [E5500_CFX_0]>],
|
||||||
[5], // Latency = 1, Repeat rate = 1
|
[5], // Latency = 1, Repeat rate = 1
|
||||||
[E5500_GPR_Bypass]>,
|
[E5500_GPR_Bypass]>,
|
||||||
InstrItinData<IIC_FPGeneral, [InstrStage<1, [E5500_DIS0, E5500_DIS1], 0>,
|
InstrItinData<IIC_FPGeneral, [InstrStage<1, [E5500_DIS0, E5500_DIS1], 0>,
|
||||||
|
@ -884,6 +884,10 @@ static Instruction *transformToIndexedCompare(GEPOperator *GEPLHS, Value *RHS,
|
|||||||
if (!GEPLHS->hasAllConstantIndices())
|
if (!GEPLHS->hasAllConstantIndices())
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
|
// Make sure the pointers have the same type.
|
||||||
|
if (GEPLHS->getType() != RHS->getType())
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
Value *PtrBase, *Index;
|
Value *PtrBase, *Index;
|
||||||
std::tie(PtrBase, Index) = getAsConstantIndexedAddress(GEPLHS, DL);
|
std::tie(PtrBase, Index) = getAsConstantIndexedAddress(GEPLHS, DL);
|
||||||
|
|
||||||
|
@ -502,7 +502,8 @@ static Instruction *combineLoadToOperationType(InstCombiner &IC, LoadInst &LI) {
|
|||||||
!DL.isNonIntegralPointerType(Ty)) {
|
!DL.isNonIntegralPointerType(Ty)) {
|
||||||
if (all_of(LI.users(), [&LI](User *U) {
|
if (all_of(LI.users(), [&LI](User *U) {
|
||||||
auto *SI = dyn_cast<StoreInst>(U);
|
auto *SI = dyn_cast<StoreInst>(U);
|
||||||
return SI && SI->getPointerOperand() != &LI;
|
return SI && SI->getPointerOperand() != &LI &&
|
||||||
|
!SI->getPointerOperand()->isSwiftError();
|
||||||
})) {
|
})) {
|
||||||
LoadInst *NewLoad = combineLoadToNewType(
|
LoadInst *NewLoad = combineLoadToNewType(
|
||||||
IC, LI,
|
IC, LI,
|
||||||
|
@ -1705,7 +1705,10 @@ static bool runIPSCCP(Module &M, const DataLayout &DL,
|
|||||||
|
|
||||||
// If this is an exact definition of this function, then we can propagate
|
// If this is an exact definition of this function, then we can propagate
|
||||||
// information about its result into callsites of it.
|
// information about its result into callsites of it.
|
||||||
if (F.hasExactDefinition())
|
// Don't touch naked functions. They may contain asm returning a
|
||||||
|
// value we don't see, so we may end up interprocedurally propagating
|
||||||
|
// the return value incorrectly.
|
||||||
|
if (F.hasExactDefinition() && !F.hasFnAttribute(Attribute::Naked))
|
||||||
Solver.AddTrackedFunction(&F);
|
Solver.AddTrackedFunction(&F);
|
||||||
|
|
||||||
// If this function only has direct calls that we can see, we can track its
|
// If this function only has direct calls that we can see, we can track its
|
||||||
|
@ -3827,13 +3827,13 @@ class AttributedType : public Type, public llvm::FoldingSetNode {
|
|||||||
|
|
||||||
friend class ASTContext; // creates these
|
friend class ASTContext; // creates these
|
||||||
|
|
||||||
AttributedType(QualType canon, Kind attrKind,
|
AttributedType(QualType canon, Kind attrKind, QualType modified,
|
||||||
QualType modified, QualType equivalent)
|
QualType equivalent)
|
||||||
: Type(Attributed, canon, canon->isDependentType(),
|
: Type(Attributed, canon, equivalent->isDependentType(),
|
||||||
canon->isInstantiationDependentType(),
|
equivalent->isInstantiationDependentType(),
|
||||||
canon->isVariablyModifiedType(),
|
equivalent->isVariablyModifiedType(),
|
||||||
canon->containsUnexpandedParameterPack()),
|
equivalent->containsUnexpandedParameterPack()),
|
||||||
ModifiedType(modified), EquivalentType(equivalent) {
|
ModifiedType(modified), EquivalentType(equivalent) {
|
||||||
AttributedTypeBits.AttrKind = attrKind;
|
AttributedTypeBits.AttrKind = attrKind;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3373,7 +3373,8 @@ def note_ovl_candidate_has_pass_object_size_params: Note<
|
|||||||
"candidate address cannot be taken because parameter %0 has "
|
"candidate address cannot be taken because parameter %0 has "
|
||||||
"pass_object_size attribute">;
|
"pass_object_size attribute">;
|
||||||
def err_diagnose_if_succeeded : Error<"%0">;
|
def err_diagnose_if_succeeded : Error<"%0">;
|
||||||
def warn_diagnose_if_succeeded : Warning<"%0">, InGroup<UserDefinedWarnings>;
|
def warn_diagnose_if_succeeded : Warning<"%0">, InGroup<UserDefinedWarnings>,
|
||||||
|
ShowInSystemHeader;
|
||||||
def note_ovl_candidate_disabled_by_function_cond_attr : Note<
|
def note_ovl_candidate_disabled_by_function_cond_attr : Note<
|
||||||
"candidate disabled: %0">;
|
"candidate disabled: %0">;
|
||||||
def note_ovl_candidate_disabled_by_extension : Note<
|
def note_ovl_candidate_disabled_by_extension : Note<
|
||||||
|
@ -675,26 +675,6 @@ namespace clang {
|
|||||||
/// to be used while performing partial ordering of function templates.
|
/// to be used while performing partial ordering of function templates.
|
||||||
unsigned ExplicitCallArguments;
|
unsigned ExplicitCallArguments;
|
||||||
|
|
||||||
/// The number of diagnose_if attributes that this overload triggered.
|
|
||||||
/// If any of the triggered attributes are errors, this won't count
|
|
||||||
/// diagnose_if warnings.
|
|
||||||
unsigned NumTriggeredDiagnoseIfs = 0;
|
|
||||||
|
|
||||||
/// Basically a TinyPtrVector<DiagnoseIfAttr *> that doesn't own the vector:
|
|
||||||
/// If NumTriggeredDiagnoseIfs is 0 or 1, this is a DiagnoseIfAttr *,
|
|
||||||
/// otherwise it's a pointer to an array of `NumTriggeredDiagnoseIfs`
|
|
||||||
/// DiagnoseIfAttr *s.
|
|
||||||
llvm::PointerUnion<DiagnoseIfAttr *, DiagnoseIfAttr **> DiagnoseIfInfo;
|
|
||||||
|
|
||||||
/// Gets an ArrayRef for the data at DiagnoseIfInfo. Note that this may give
|
|
||||||
/// you a pointer into DiagnoseIfInfo.
|
|
||||||
ArrayRef<DiagnoseIfAttr *> getDiagnoseIfInfo() const {
|
|
||||||
auto *Ptr = NumTriggeredDiagnoseIfs <= 1
|
|
||||||
? DiagnoseIfInfo.getAddrOfPtr1()
|
|
||||||
: DiagnoseIfInfo.get<DiagnoseIfAttr **>();
|
|
||||||
return {Ptr, NumTriggeredDiagnoseIfs};
|
|
||||||
}
|
|
||||||
|
|
||||||
union {
|
union {
|
||||||
DeductionFailureInfo DeductionFailure;
|
DeductionFailureInfo DeductionFailure;
|
||||||
|
|
||||||
@ -759,9 +739,8 @@ namespace clang {
|
|||||||
SmallVector<OverloadCandidate, 16> Candidates;
|
SmallVector<OverloadCandidate, 16> Candidates;
|
||||||
llvm::SmallPtrSet<Decl *, 16> Functions;
|
llvm::SmallPtrSet<Decl *, 16> Functions;
|
||||||
|
|
||||||
// Allocator for ConversionSequenceLists and DiagnoseIfAttr* arrays.
|
// Allocator for ConversionSequenceLists. We store the first few of these
|
||||||
// We store the first few of each of these inline to avoid allocation for
|
// inline to avoid allocation for small sets.
|
||||||
// small sets.
|
|
||||||
llvm::BumpPtrAllocator SlabAllocator;
|
llvm::BumpPtrAllocator SlabAllocator;
|
||||||
|
|
||||||
SourceLocation Loc;
|
SourceLocation Loc;
|
||||||
@ -776,6 +755,8 @@ namespace clang {
|
|||||||
/// from the slab allocator.
|
/// from the slab allocator.
|
||||||
/// FIXME: It would probably be nice to have a SmallBumpPtrAllocator
|
/// FIXME: It would probably be nice to have a SmallBumpPtrAllocator
|
||||||
/// instead.
|
/// instead.
|
||||||
|
/// FIXME: Now that this only allocates ImplicitConversionSequences, do we
|
||||||
|
/// want to un-generalize this?
|
||||||
template <typename T>
|
template <typename T>
|
||||||
T *slabAllocate(unsigned N) {
|
T *slabAllocate(unsigned N) {
|
||||||
// It's simpler if this doesn't need to consider alignment.
|
// It's simpler if this doesn't need to consider alignment.
|
||||||
@ -809,11 +790,6 @@ namespace clang {
|
|||||||
SourceLocation getLocation() const { return Loc; }
|
SourceLocation getLocation() const { return Loc; }
|
||||||
CandidateSetKind getKind() const { return Kind; }
|
CandidateSetKind getKind() const { return Kind; }
|
||||||
|
|
||||||
/// Make a DiagnoseIfAttr* array in a block of memory that will live for
|
|
||||||
/// as long as this OverloadCandidateSet. Returns a pointer to the start
|
|
||||||
/// of that array.
|
|
||||||
DiagnoseIfAttr **addDiagnoseIfComplaints(ArrayRef<DiagnoseIfAttr *> CA);
|
|
||||||
|
|
||||||
/// \brief Determine when this overload candidate will be new to the
|
/// \brief Determine when this overload candidate will be new to the
|
||||||
/// overload set.
|
/// overload set.
|
||||||
bool isNewCandidate(Decl *F) {
|
bool isNewCandidate(Decl *F) {
|
||||||
|
@ -2532,14 +2532,14 @@ class Sema {
|
|||||||
void AddMethodCandidate(DeclAccessPair FoundDecl,
|
void AddMethodCandidate(DeclAccessPair FoundDecl,
|
||||||
QualType ObjectType,
|
QualType ObjectType,
|
||||||
Expr::Classification ObjectClassification,
|
Expr::Classification ObjectClassification,
|
||||||
Expr *ThisArg, ArrayRef<Expr *> Args,
|
ArrayRef<Expr *> Args,
|
||||||
OverloadCandidateSet& CandidateSet,
|
OverloadCandidateSet& CandidateSet,
|
||||||
bool SuppressUserConversion = false);
|
bool SuppressUserConversion = false);
|
||||||
void AddMethodCandidate(CXXMethodDecl *Method,
|
void AddMethodCandidate(CXXMethodDecl *Method,
|
||||||
DeclAccessPair FoundDecl,
|
DeclAccessPair FoundDecl,
|
||||||
CXXRecordDecl *ActingContext, QualType ObjectType,
|
CXXRecordDecl *ActingContext, QualType ObjectType,
|
||||||
Expr::Classification ObjectClassification,
|
Expr::Classification ObjectClassification,
|
||||||
Expr *ThisArg, ArrayRef<Expr *> Args,
|
ArrayRef<Expr *> Args,
|
||||||
OverloadCandidateSet& CandidateSet,
|
OverloadCandidateSet& CandidateSet,
|
||||||
bool SuppressUserConversions = false,
|
bool SuppressUserConversions = false,
|
||||||
bool PartialOverloading = false,
|
bool PartialOverloading = false,
|
||||||
@ -2550,7 +2550,6 @@ class Sema {
|
|||||||
TemplateArgumentListInfo *ExplicitTemplateArgs,
|
TemplateArgumentListInfo *ExplicitTemplateArgs,
|
||||||
QualType ObjectType,
|
QualType ObjectType,
|
||||||
Expr::Classification ObjectClassification,
|
Expr::Classification ObjectClassification,
|
||||||
Expr *ThisArg,
|
|
||||||
ArrayRef<Expr *> Args,
|
ArrayRef<Expr *> Args,
|
||||||
OverloadCandidateSet& CandidateSet,
|
OverloadCandidateSet& CandidateSet,
|
||||||
bool SuppressUserConversions = false,
|
bool SuppressUserConversions = false,
|
||||||
@ -2624,37 +2623,27 @@ class Sema {
|
|||||||
EnableIfAttr *CheckEnableIf(FunctionDecl *Function, ArrayRef<Expr *> Args,
|
EnableIfAttr *CheckEnableIf(FunctionDecl *Function, ArrayRef<Expr *> Args,
|
||||||
bool MissingImplicitThis = false);
|
bool MissingImplicitThis = false);
|
||||||
|
|
||||||
/// Check the diagnose_if attributes on the given function. Returns the
|
/// Emit diagnostics for the diagnose_if attributes on Function, ignoring any
|
||||||
/// first succesful fatal attribute, or null if calling Function(Args) isn't
|
/// non-ArgDependent DiagnoseIfAttrs.
|
||||||
/// an error.
|
|
||||||
///
|
///
|
||||||
/// This only considers ArgDependent DiagnoseIfAttrs.
|
/// Argument-dependent diagnose_if attributes should be checked each time a
|
||||||
|
/// function is used as a direct callee of a function call.
|
||||||
///
|
///
|
||||||
/// This will populate Nonfatal with all non-error DiagnoseIfAttrs that
|
/// Returns true if any errors were emitted.
|
||||||
/// succeed. If this function returns non-null, the contents of Nonfatal are
|
bool diagnoseArgDependentDiagnoseIfAttrs(const FunctionDecl *Function,
|
||||||
/// unspecified.
|
const Expr *ThisArg,
|
||||||
DiagnoseIfAttr *
|
ArrayRef<const Expr *> Args,
|
||||||
checkArgDependentDiagnoseIf(FunctionDecl *Function, ArrayRef<Expr *> Args,
|
SourceLocation Loc);
|
||||||
SmallVectorImpl<DiagnoseIfAttr *> &Nonfatal,
|
|
||||||
bool MissingImplicitThis = false,
|
|
||||||
Expr *ThisArg = nullptr);
|
|
||||||
|
|
||||||
/// Check the diagnose_if expressions on the given function. Returns the
|
/// Emit diagnostics for the diagnose_if attributes on Function, ignoring any
|
||||||
/// first succesful fatal attribute, or null if using Function isn't
|
/// ArgDependent DiagnoseIfAttrs.
|
||||||
/// an error.
|
|
||||||
///
|
///
|
||||||
/// This ignores all ArgDependent DiagnoseIfAttrs.
|
/// Argument-independent diagnose_if attributes should be checked on every use
|
||||||
|
/// of a function.
|
||||||
///
|
///
|
||||||
/// This will populate Nonfatal with all non-error DiagnoseIfAttrs that
|
/// Returns true if any errors were emitted.
|
||||||
/// succeed. If this function returns non-null, the contents of Nonfatal are
|
bool diagnoseArgIndependentDiagnoseIfAttrs(const FunctionDecl *Function,
|
||||||
/// unspecified.
|
SourceLocation Loc);
|
||||||
DiagnoseIfAttr *
|
|
||||||
checkArgIndependentDiagnoseIf(FunctionDecl *Function,
|
|
||||||
SmallVectorImpl<DiagnoseIfAttr *> &Nonfatal);
|
|
||||||
|
|
||||||
/// Emits the diagnostic contained in the given DiagnoseIfAttr at Loc. Also
|
|
||||||
/// emits a note about the location of said attribute.
|
|
||||||
void emitDiagnoseIfDiagnostic(SourceLocation Loc, const DiagnoseIfAttr *DIA);
|
|
||||||
|
|
||||||
/// Returns whether the given function's address can be taken or not,
|
/// Returns whether the given function's address can be taken or not,
|
||||||
/// optionally emitting a diagnostic if the address can't be taken.
|
/// optionally emitting a diagnostic if the address can't be taken.
|
||||||
@ -9914,8 +9903,8 @@ class Sema {
|
|||||||
SourceLocation Loc);
|
SourceLocation Loc);
|
||||||
|
|
||||||
void checkCall(NamedDecl *FDecl, const FunctionProtoType *Proto,
|
void checkCall(NamedDecl *FDecl, const FunctionProtoType *Proto,
|
||||||
ArrayRef<const Expr *> Args, bool IsMemberFunction,
|
const Expr *ThisArg, ArrayRef<const Expr *> Args,
|
||||||
SourceLocation Loc, SourceRange Range,
|
bool IsMemberFunction, SourceLocation Loc, SourceRange Range,
|
||||||
VariadicCallType CallType);
|
VariadicCallType CallType);
|
||||||
|
|
||||||
bool CheckObjCString(Expr *Arg);
|
bool CheckObjCString(Expr *Arg);
|
||||||
|
@ -2362,7 +2362,14 @@ static unsigned getBaseIndex(const CXXRecordDecl *Derived,
|
|||||||
/// Extract the value of a character from a string literal.
|
/// Extract the value of a character from a string literal.
|
||||||
static APSInt extractStringLiteralCharacter(EvalInfo &Info, const Expr *Lit,
|
static APSInt extractStringLiteralCharacter(EvalInfo &Info, const Expr *Lit,
|
||||||
uint64_t Index) {
|
uint64_t Index) {
|
||||||
// FIXME: Support ObjCEncodeExpr, MakeStringConstant
|
// FIXME: Support MakeStringConstant
|
||||||
|
if (const auto *ObjCEnc = dyn_cast<ObjCEncodeExpr>(Lit)) {
|
||||||
|
std::string Str;
|
||||||
|
Info.Ctx.getObjCEncodingForType(ObjCEnc->getEncodedType(), Str);
|
||||||
|
assert(Index <= Str.size() && "Index too large");
|
||||||
|
return APSInt::getUnsigned(Str.c_str()[Index]);
|
||||||
|
}
|
||||||
|
|
||||||
if (auto PE = dyn_cast<PredefinedExpr>(Lit))
|
if (auto PE = dyn_cast<PredefinedExpr>(Lit))
|
||||||
Lit = PE->getFunctionName();
|
Lit = PE->getFunctionName();
|
||||||
const StringLiteral *S = cast<StringLiteral>(Lit);
|
const StringLiteral *S = cast<StringLiteral>(Lit);
|
||||||
|
@ -737,7 +737,7 @@ CodeGenTypes::getCGRecordLayout(const RecordDecl *RD) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool CodeGenTypes::isPointerZeroInitializable(QualType T) {
|
bool CodeGenTypes::isPointerZeroInitializable(QualType T) {
|
||||||
assert (T->isAnyPointerType() && "Invalid type");
|
assert((T->isAnyPointerType() || T->isBlockPointerType()) && "Invalid type");
|
||||||
return isZeroInitializable(T);
|
return isZeroInitializable(T);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2426,11 +2426,12 @@ static void CheckNonNullArguments(Sema &S,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Handles the checks for format strings, non-POD arguments to vararg
|
/// Handles the checks for format strings, non-POD arguments to vararg
|
||||||
/// functions, and NULL arguments passed to non-NULL parameters.
|
/// functions, NULL arguments passed to non-NULL parameters, and diagnose_if
|
||||||
|
/// attributes.
|
||||||
void Sema::checkCall(NamedDecl *FDecl, const FunctionProtoType *Proto,
|
void Sema::checkCall(NamedDecl *FDecl, const FunctionProtoType *Proto,
|
||||||
ArrayRef<const Expr *> Args, bool IsMemberFunction,
|
const Expr *ThisArg, ArrayRef<const Expr *> Args,
|
||||||
SourceLocation Loc, SourceRange Range,
|
bool IsMemberFunction, SourceLocation Loc,
|
||||||
VariadicCallType CallType) {
|
SourceRange Range, VariadicCallType CallType) {
|
||||||
// FIXME: We should check as much as we can in the template definition.
|
// FIXME: We should check as much as we can in the template definition.
|
||||||
if (CurContext->isDependentContext())
|
if (CurContext->isDependentContext())
|
||||||
return;
|
return;
|
||||||
@ -2477,6 +2478,9 @@ void Sema::checkCall(NamedDecl *FDecl, const FunctionProtoType *Proto,
|
|||||||
CheckArgumentWithTypeTag(I, Args.data());
|
CheckArgumentWithTypeTag(I, Args.data());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (FD)
|
||||||
|
diagnoseArgDependentDiagnoseIfAttrs(FD, ThisArg, Args, Loc);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// CheckConstructorCall - Check a constructor call for correctness and safety
|
/// CheckConstructorCall - Check a constructor call for correctness and safety
|
||||||
@ -2487,8 +2491,8 @@ void Sema::CheckConstructorCall(FunctionDecl *FDecl,
|
|||||||
SourceLocation Loc) {
|
SourceLocation Loc) {
|
||||||
VariadicCallType CallType =
|
VariadicCallType CallType =
|
||||||
Proto->isVariadic() ? VariadicConstructor : VariadicDoesNotApply;
|
Proto->isVariadic() ? VariadicConstructor : VariadicDoesNotApply;
|
||||||
checkCall(FDecl, Proto, Args, /*IsMemberFunction=*/true, Loc, SourceRange(),
|
checkCall(FDecl, Proto, /*ThisArg=*/nullptr, Args, /*IsMemberFunction=*/true,
|
||||||
CallType);
|
Loc, SourceRange(), CallType);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// CheckFunctionCall - Check a direct function call for various correctness
|
/// CheckFunctionCall - Check a direct function call for various correctness
|
||||||
@ -2503,14 +2507,20 @@ bool Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall,
|
|||||||
TheCall->getCallee());
|
TheCall->getCallee());
|
||||||
Expr** Args = TheCall->getArgs();
|
Expr** Args = TheCall->getArgs();
|
||||||
unsigned NumArgs = TheCall->getNumArgs();
|
unsigned NumArgs = TheCall->getNumArgs();
|
||||||
|
|
||||||
|
Expr *ImplicitThis = nullptr;
|
||||||
if (IsMemberOperatorCall) {
|
if (IsMemberOperatorCall) {
|
||||||
// If this is a call to a member operator, hide the first argument
|
// If this is a call to a member operator, hide the first argument
|
||||||
// from checkCall.
|
// from checkCall.
|
||||||
// FIXME: Our choice of AST representation here is less than ideal.
|
// FIXME: Our choice of AST representation here is less than ideal.
|
||||||
|
ImplicitThis = Args[0];
|
||||||
++Args;
|
++Args;
|
||||||
--NumArgs;
|
--NumArgs;
|
||||||
}
|
} else if (IsMemberFunction)
|
||||||
checkCall(FDecl, Proto, llvm::makeArrayRef(Args, NumArgs),
|
ImplicitThis =
|
||||||
|
cast<CXXMemberCallExpr>(TheCall)->getImplicitObjectArgument();
|
||||||
|
|
||||||
|
checkCall(FDecl, Proto, ImplicitThis, llvm::makeArrayRef(Args, NumArgs),
|
||||||
IsMemberFunction, TheCall->getRParenLoc(),
|
IsMemberFunction, TheCall->getRParenLoc(),
|
||||||
TheCall->getCallee()->getSourceRange(), CallType);
|
TheCall->getCallee()->getSourceRange(), CallType);
|
||||||
|
|
||||||
@ -2546,8 +2556,8 @@ bool Sema::CheckObjCMethodCall(ObjCMethodDecl *Method, SourceLocation lbrac,
|
|||||||
VariadicCallType CallType =
|
VariadicCallType CallType =
|
||||||
Method->isVariadic() ? VariadicMethod : VariadicDoesNotApply;
|
Method->isVariadic() ? VariadicMethod : VariadicDoesNotApply;
|
||||||
|
|
||||||
checkCall(Method, nullptr, Args,
|
checkCall(Method, nullptr, /*ThisArg=*/nullptr, Args,
|
||||||
/*IsMemberFunction=*/false, lbrac, Method->getSourceRange(),
|
/*IsMemberFunction=*/false, lbrac, Method->getSourceRange(),
|
||||||
CallType);
|
CallType);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@ -2576,7 +2586,7 @@ bool Sema::CheckPointerCall(NamedDecl *NDecl, CallExpr *TheCall,
|
|||||||
CallType = VariadicFunction;
|
CallType = VariadicFunction;
|
||||||
}
|
}
|
||||||
|
|
||||||
checkCall(NDecl, Proto,
|
checkCall(NDecl, Proto, /*ThisArg=*/nullptr,
|
||||||
llvm::makeArrayRef(TheCall->getArgs(), TheCall->getNumArgs()),
|
llvm::makeArrayRef(TheCall->getArgs(), TheCall->getNumArgs()),
|
||||||
/*IsMemberFunction=*/false, TheCall->getRParenLoc(),
|
/*IsMemberFunction=*/false, TheCall->getRParenLoc(),
|
||||||
TheCall->getCallee()->getSourceRange(), CallType);
|
TheCall->getCallee()->getSourceRange(), CallType);
|
||||||
@ -2589,7 +2599,7 @@ bool Sema::CheckPointerCall(NamedDecl *NDecl, CallExpr *TheCall,
|
|||||||
bool Sema::CheckOtherCall(CallExpr *TheCall, const FunctionProtoType *Proto) {
|
bool Sema::CheckOtherCall(CallExpr *TheCall, const FunctionProtoType *Proto) {
|
||||||
VariadicCallType CallType = getVariadicCallType(/*FDecl=*/nullptr, Proto,
|
VariadicCallType CallType = getVariadicCallType(/*FDecl=*/nullptr, Proto,
|
||||||
TheCall->getCallee());
|
TheCall->getCallee());
|
||||||
checkCall(/*FDecl=*/nullptr, Proto,
|
checkCall(/*FDecl=*/nullptr, Proto, /*ThisArg=*/nullptr,
|
||||||
llvm::makeArrayRef(TheCall->getArgs(), TheCall->getNumArgs()),
|
llvm::makeArrayRef(TheCall->getArgs(), TheCall->getNumArgs()),
|
||||||
/*IsMemberFunction=*/false, TheCall->getRParenLoc(),
|
/*IsMemberFunction=*/false, TheCall->getRParenLoc(),
|
||||||
TheCall->getCallee()->getSourceRange(), CallType);
|
TheCall->getCallee()->getSourceRange(), CallType);
|
||||||
|
@ -342,7 +342,6 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// See if this is a deleted function.
|
// See if this is a deleted function.
|
||||||
SmallVector<DiagnoseIfAttr *, 4> DiagnoseIfWarnings;
|
|
||||||
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
|
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
|
||||||
if (FD->isDeleted()) {
|
if (FD->isDeleted()) {
|
||||||
auto *Ctor = dyn_cast<CXXConstructorDecl>(FD);
|
auto *Ctor = dyn_cast<CXXConstructorDecl>(FD);
|
||||||
@ -365,11 +364,8 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc,
|
|||||||
if (getLangOpts().CUDA && !CheckCUDACall(Loc, FD))
|
if (getLangOpts().CUDA && !CheckCUDACall(Loc, FD))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (const DiagnoseIfAttr *A =
|
if (diagnoseArgIndependentDiagnoseIfAttrs(FD, Loc))
|
||||||
checkArgIndependentDiagnoseIf(FD, DiagnoseIfWarnings)) {
|
|
||||||
emitDiagnoseIfDiagnostic(Loc, A);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// [OpenMP 4.0], 2.15 declare reduction Directive, Restrictions
|
// [OpenMP 4.0], 2.15 declare reduction Directive, Restrictions
|
||||||
@ -385,9 +381,6 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const auto *W : DiagnoseIfWarnings)
|
|
||||||
emitDiagnoseIfDiagnostic(Loc, W);
|
|
||||||
|
|
||||||
DiagnoseAvailabilityOfDecl(*this, D, Loc, UnknownObjCClass,
|
DiagnoseAvailabilityOfDecl(*this, D, Loc, UnknownObjCClass,
|
||||||
ObjCPropertyAccess);
|
ObjCPropertyAccess);
|
||||||
|
|
||||||
@ -5189,16 +5182,6 @@ static void checkDirectCallValidity(Sema &S, const Expr *Fn,
|
|||||||
<< Attr->getCond()->getSourceRange() << Attr->getMessage();
|
<< Attr->getCond()->getSourceRange() << Attr->getMessage();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
SmallVector<DiagnoseIfAttr *, 4> Nonfatal;
|
|
||||||
if (const DiagnoseIfAttr *Attr = S.checkArgDependentDiagnoseIf(
|
|
||||||
Callee, ArgExprs, Nonfatal, /*MissingImplicitThis=*/true)) {
|
|
||||||
S.emitDiagnoseIfDiagnostic(Fn->getLocStart(), Attr);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const auto *W : Nonfatal)
|
|
||||||
S.emitDiagnoseIfDiagnostic(Fn->getLocStart(), W);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ActOnCallExpr - Handle a call to Fn with the specified array of arguments.
|
/// ActOnCallExpr - Handle a call to Fn with the specified array of arguments.
|
||||||
|
@ -6712,6 +6712,11 @@ ExprResult Sema::BuildCXXMemberCallExpr(Expr *E, NamedDecl *FoundDecl,
|
|||||||
CXXMemberCallExpr *CE =
|
CXXMemberCallExpr *CE =
|
||||||
new (Context) CXXMemberCallExpr(Context, ME, None, ResultType, VK,
|
new (Context) CXXMemberCallExpr(Context, ME, None, ResultType, VK,
|
||||||
Exp.get()->getLocEnd());
|
Exp.get()->getLocEnd());
|
||||||
|
|
||||||
|
if (CheckFunctionCall(Method, CE,
|
||||||
|
Method->getType()->castAs<FunctionProtoType>()))
|
||||||
|
return ExprError();
|
||||||
|
|
||||||
return CE;
|
return CE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2960,7 +2960,6 @@ Sema::SpecialMemberOverloadResult *Sema::LookupSpecialMember(CXXRecordDecl *RD,
|
|||||||
if (CXXMethodDecl *M = dyn_cast<CXXMethodDecl>(Cand->getUnderlyingDecl())) {
|
if (CXXMethodDecl *M = dyn_cast<CXXMethodDecl>(Cand->getUnderlyingDecl())) {
|
||||||
if (SM == CXXCopyAssignment || SM == CXXMoveAssignment)
|
if (SM == CXXCopyAssignment || SM == CXXMoveAssignment)
|
||||||
AddMethodCandidate(M, Cand, RD, ThisTy, Classification,
|
AddMethodCandidate(M, Cand, RD, ThisTy, Classification,
|
||||||
/*ThisArg=*/nullptr,
|
|
||||||
llvm::makeArrayRef(&Arg, NumArgs), OCS, true);
|
llvm::makeArrayRef(&Arg, NumArgs), OCS, true);
|
||||||
else if (CtorInfo)
|
else if (CtorInfo)
|
||||||
AddOverloadCandidate(CtorInfo.Constructor, CtorInfo.FoundDecl,
|
AddOverloadCandidate(CtorInfo.Constructor, CtorInfo.FoundDecl,
|
||||||
@ -2973,7 +2972,7 @@ Sema::SpecialMemberOverloadResult *Sema::LookupSpecialMember(CXXRecordDecl *RD,
|
|||||||
if (SM == CXXCopyAssignment || SM == CXXMoveAssignment)
|
if (SM == CXXCopyAssignment || SM == CXXMoveAssignment)
|
||||||
AddMethodTemplateCandidate(
|
AddMethodTemplateCandidate(
|
||||||
Tmpl, Cand, RD, nullptr, ThisTy, Classification,
|
Tmpl, Cand, RD, nullptr, ThisTy, Classification,
|
||||||
/*ThisArg=*/nullptr, llvm::makeArrayRef(&Arg, NumArgs), OCS, true);
|
llvm::makeArrayRef(&Arg, NumArgs), OCS, true);
|
||||||
else if (CtorInfo)
|
else if (CtorInfo)
|
||||||
AddTemplateOverloadCandidate(
|
AddTemplateOverloadCandidate(
|
||||||
CtorInfo.ConstructorTmpl, CtorInfo.FoundDecl, nullptr,
|
CtorInfo.ConstructorTmpl, CtorInfo.FoundDecl, nullptr,
|
||||||
|
@ -839,20 +839,12 @@ void OverloadCandidateSet::destroyCandidates() {
|
|||||||
|
|
||||||
void OverloadCandidateSet::clear() {
|
void OverloadCandidateSet::clear() {
|
||||||
destroyCandidates();
|
destroyCandidates();
|
||||||
// DiagnoseIfAttrs are just pointers, so we don't need to destroy them.
|
|
||||||
SlabAllocator.Reset();
|
SlabAllocator.Reset();
|
||||||
NumInlineBytesUsed = 0;
|
NumInlineBytesUsed = 0;
|
||||||
Candidates.clear();
|
Candidates.clear();
|
||||||
Functions.clear();
|
Functions.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
DiagnoseIfAttr **
|
|
||||||
OverloadCandidateSet::addDiagnoseIfComplaints(ArrayRef<DiagnoseIfAttr *> CA) {
|
|
||||||
auto *DIA = slabAllocate<DiagnoseIfAttr *>(CA.size());
|
|
||||||
std::uninitialized_copy(CA.begin(), CA.end(), DIA);
|
|
||||||
return DIA;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
class UnbridgedCastsSet {
|
class UnbridgedCastsSet {
|
||||||
struct Entry {
|
struct Entry {
|
||||||
@ -5831,28 +5823,6 @@ static bool IsAcceptableNonMemberOperatorCandidate(ASTContext &Context,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void initDiagnoseIfComplaint(Sema &S, OverloadCandidateSet &CandidateSet,
|
|
||||||
OverloadCandidate &Candidate,
|
|
||||||
FunctionDecl *Function,
|
|
||||||
ArrayRef<Expr *> Args,
|
|
||||||
bool MissingImplicitThis = false,
|
|
||||||
Expr *ExplicitThis = nullptr) {
|
|
||||||
SmallVector<DiagnoseIfAttr *, 8> Results;
|
|
||||||
if (DiagnoseIfAttr *DIA = S.checkArgDependentDiagnoseIf(
|
|
||||||
Function, Args, Results, MissingImplicitThis, ExplicitThis)) {
|
|
||||||
Results.clear();
|
|
||||||
Results.push_back(DIA);
|
|
||||||
}
|
|
||||||
|
|
||||||
Candidate.NumTriggeredDiagnoseIfs = Results.size();
|
|
||||||
if (Results.empty())
|
|
||||||
Candidate.DiagnoseIfInfo = nullptr;
|
|
||||||
else if (Results.size() == 1)
|
|
||||||
Candidate.DiagnoseIfInfo = Results[0];
|
|
||||||
else
|
|
||||||
Candidate.DiagnoseIfInfo = CandidateSet.addDiagnoseIfComplaints(Results);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// AddOverloadCandidate - Adds the given function to the set of
|
/// AddOverloadCandidate - Adds the given function to the set of
|
||||||
/// candidate functions, using the given function call arguments. If
|
/// candidate functions, using the given function call arguments. If
|
||||||
/// @p SuppressUserConversions, then don't allow user-defined
|
/// @p SuppressUserConversions, then don't allow user-defined
|
||||||
@ -5886,10 +5856,9 @@ Sema::AddOverloadCandidate(FunctionDecl *Function,
|
|||||||
// object argument (C++ [over.call.func]p3), and the acting context
|
// object argument (C++ [over.call.func]p3), and the acting context
|
||||||
// is irrelevant.
|
// is irrelevant.
|
||||||
AddMethodCandidate(Method, FoundDecl, Method->getParent(), QualType(),
|
AddMethodCandidate(Method, FoundDecl, Method->getParent(), QualType(),
|
||||||
Expr::Classification::makeSimpleLValue(),
|
Expr::Classification::makeSimpleLValue(), Args,
|
||||||
/*ThisArg=*/nullptr, Args, CandidateSet,
|
CandidateSet, SuppressUserConversions,
|
||||||
SuppressUserConversions, PartialOverloading,
|
PartialOverloading, EarlyConversions);
|
||||||
EarlyConversions);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// We treat a constructor like a non-member function, since its object
|
// We treat a constructor like a non-member function, since its object
|
||||||
@ -6050,8 +6019,6 @@ Sema::AddOverloadCandidate(FunctionDecl *Function,
|
|||||||
Candidate.FailureKind = ovl_fail_ext_disabled;
|
Candidate.FailureKind = ovl_fail_ext_disabled;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
initDiagnoseIfComplaint(*this, CandidateSet, Candidate, Function, Args);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ObjCMethodDecl *
|
ObjCMethodDecl *
|
||||||
@ -6260,85 +6227,73 @@ EnableIfAttr *Sema::CheckEnableIf(FunctionDecl *Function, ArrayRef<Expr *> Args,
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool gatherDiagnoseIfAttrs(FunctionDecl *Function, bool ArgDependent,
|
|
||||||
SmallVectorImpl<DiagnoseIfAttr *> &Errors,
|
|
||||||
SmallVectorImpl<DiagnoseIfAttr *> &Nonfatal) {
|
|
||||||
for (auto *DIA : Function->specific_attrs<DiagnoseIfAttr>())
|
|
||||||
if (ArgDependent == DIA->getArgDependent()) {
|
|
||||||
if (DIA->isError())
|
|
||||||
Errors.push_back(DIA);
|
|
||||||
else
|
|
||||||
Nonfatal.push_back(DIA);
|
|
||||||
}
|
|
||||||
|
|
||||||
return !Errors.empty() || !Nonfatal.empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename CheckFn>
|
template <typename CheckFn>
|
||||||
static DiagnoseIfAttr *
|
static bool diagnoseDiagnoseIfAttrsWith(Sema &S, const FunctionDecl *FD,
|
||||||
checkDiagnoseIfAttrsWith(const SmallVectorImpl<DiagnoseIfAttr *> &Errors,
|
bool ArgDependent, SourceLocation Loc,
|
||||||
SmallVectorImpl<DiagnoseIfAttr *> &Nonfatal,
|
CheckFn &&IsSuccessful) {
|
||||||
CheckFn &&IsSuccessful) {
|
SmallVector<const DiagnoseIfAttr *, 8> Attrs;
|
||||||
|
for (const auto *DIA : FD->specific_attrs<DiagnoseIfAttr>()) {
|
||||||
|
if (ArgDependent == DIA->getArgDependent())
|
||||||
|
Attrs.push_back(DIA);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Common case: No diagnose_if attributes, so we can quit early.
|
||||||
|
if (Attrs.empty())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
auto WarningBegin = std::stable_partition(
|
||||||
|
Attrs.begin(), Attrs.end(),
|
||||||
|
[](const DiagnoseIfAttr *DIA) { return DIA->isError(); });
|
||||||
|
|
||||||
// Note that diagnose_if attributes are late-parsed, so they appear in the
|
// Note that diagnose_if attributes are late-parsed, so they appear in the
|
||||||
// correct order (unlike enable_if attributes).
|
// correct order (unlike enable_if attributes).
|
||||||
auto ErrAttr = llvm::find_if(Errors, IsSuccessful);
|
auto ErrAttr = llvm::find_if(llvm::make_range(Attrs.begin(), WarningBegin),
|
||||||
if (ErrAttr != Errors.end())
|
IsSuccessful);
|
||||||
return *ErrAttr;
|
if (ErrAttr != WarningBegin) {
|
||||||
|
const DiagnoseIfAttr *DIA = *ErrAttr;
|
||||||
|
S.Diag(Loc, diag::err_diagnose_if_succeeded) << DIA->getMessage();
|
||||||
|
S.Diag(DIA->getLocation(), diag::note_from_diagnose_if)
|
||||||
|
<< DIA->getParent() << DIA->getCond()->getSourceRange();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
llvm::erase_if(Nonfatal, [&](DiagnoseIfAttr *A) { return !IsSuccessful(A); });
|
for (const auto *DIA : llvm::make_range(WarningBegin, Attrs.end()))
|
||||||
return nullptr;
|
if (IsSuccessful(DIA)) {
|
||||||
|
S.Diag(Loc, diag::warn_diagnose_if_succeeded) << DIA->getMessage();
|
||||||
|
S.Diag(DIA->getLocation(), diag::note_from_diagnose_if)
|
||||||
|
<< DIA->getParent() << DIA->getCond()->getSourceRange();
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
DiagnoseIfAttr *
|
bool Sema::diagnoseArgDependentDiagnoseIfAttrs(const FunctionDecl *Function,
|
||||||
Sema::checkArgDependentDiagnoseIf(FunctionDecl *Function, ArrayRef<Expr *> Args,
|
const Expr *ThisArg,
|
||||||
SmallVectorImpl<DiagnoseIfAttr *> &Nonfatal,
|
ArrayRef<const Expr *> Args,
|
||||||
bool MissingImplicitThis,
|
SourceLocation Loc) {
|
||||||
Expr *ThisArg) {
|
return diagnoseDiagnoseIfAttrsWith(
|
||||||
SmallVector<DiagnoseIfAttr *, 4> Errors;
|
*this, Function, /*ArgDependent=*/true, Loc,
|
||||||
if (!gatherDiagnoseIfAttrs(Function, /*ArgDependent=*/true, Errors, Nonfatal))
|
[&](const DiagnoseIfAttr *DIA) {
|
||||||
return nullptr;
|
APValue Result;
|
||||||
|
// It's sane to use the same Args for any redecl of this function, since
|
||||||
SFINAETrap Trap(*this);
|
// EvaluateWithSubstitution only cares about the position of each
|
||||||
SmallVector<Expr *, 16> ConvertedArgs;
|
// argument in the arg list, not the ParmVarDecl* it maps to.
|
||||||
Expr *ConvertedThis;
|
if (!DIA->getCond()->EvaluateWithSubstitution(
|
||||||
if (!convertArgsForAvailabilityChecks(*this, Function, ThisArg, Args, Trap,
|
Result, Context, DIA->getParent(), Args, ThisArg))
|
||||||
MissingImplicitThis, ConvertedThis,
|
return false;
|
||||||
ConvertedArgs))
|
return Result.isInt() && Result.getInt().getBoolValue();
|
||||||
return nullptr;
|
});
|
||||||
|
|
||||||
return checkDiagnoseIfAttrsWith(Errors, Nonfatal, [&](DiagnoseIfAttr *DIA) {
|
|
||||||
APValue Result;
|
|
||||||
// It's sane to use the same ConvertedArgs for any redecl of this function,
|
|
||||||
// since EvaluateWithSubstitution only cares about the position of each
|
|
||||||
// argument in the arg list, not the ParmVarDecl* it maps to.
|
|
||||||
if (!DIA->getCond()->EvaluateWithSubstitution(
|
|
||||||
Result, Context, DIA->getParent(), ConvertedArgs, ConvertedThis))
|
|
||||||
return false;
|
|
||||||
return Result.isInt() && Result.getInt().getBoolValue();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DiagnoseIfAttr *Sema::checkArgIndependentDiagnoseIf(
|
bool Sema::diagnoseArgIndependentDiagnoseIfAttrs(const FunctionDecl *Function,
|
||||||
FunctionDecl *Function, SmallVectorImpl<DiagnoseIfAttr *> &Nonfatal) {
|
SourceLocation Loc) {
|
||||||
SmallVector<DiagnoseIfAttr *, 4> Errors;
|
return diagnoseDiagnoseIfAttrsWith(
|
||||||
if (!gatherDiagnoseIfAttrs(Function, /*ArgDependent=*/false, Errors,
|
*this, Function, /*ArgDependent=*/false, Loc,
|
||||||
Nonfatal))
|
[&](const DiagnoseIfAttr *DIA) {
|
||||||
return nullptr;
|
bool Result;
|
||||||
|
return DIA->getCond()->EvaluateAsBooleanCondition(Result, Context) &&
|
||||||
return checkDiagnoseIfAttrsWith(Errors, Nonfatal, [&](DiagnoseIfAttr *DIA) {
|
Result;
|
||||||
bool Result;
|
});
|
||||||
return DIA->getCond()->EvaluateAsBooleanCondition(Result, Context) &&
|
|
||||||
Result;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void Sema::emitDiagnoseIfDiagnostic(SourceLocation Loc,
|
|
||||||
const DiagnoseIfAttr *DIA) {
|
|
||||||
auto Code = DIA->isError() ? diag::err_diagnose_if_succeeded
|
|
||||||
: diag::warn_diagnose_if_succeeded;
|
|
||||||
Diag(Loc, Code) << DIA->getMessage();
|
|
||||||
Diag(DIA->getLocation(), diag::note_from_diagnose_if)
|
|
||||||
<< DIA->getParent() << DIA->getCond()->getSourceRange();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Add all of the function declarations in the given function set to
|
/// \brief Add all of the function declarations in the given function set to
|
||||||
@ -6356,8 +6311,8 @@ void Sema::AddFunctionCandidates(const UnresolvedSetImpl &Fns,
|
|||||||
AddMethodCandidate(cast<CXXMethodDecl>(FD), F.getPair(),
|
AddMethodCandidate(cast<CXXMethodDecl>(FD), F.getPair(),
|
||||||
cast<CXXMethodDecl>(FD)->getParent(),
|
cast<CXXMethodDecl>(FD)->getParent(),
|
||||||
Args[0]->getType(), Args[0]->Classify(Context),
|
Args[0]->getType(), Args[0]->Classify(Context),
|
||||||
Args[0], Args.slice(1), CandidateSet,
|
Args.slice(1), CandidateSet, SuppressUserConversions,
|
||||||
SuppressUserConversions, PartialOverloading);
|
PartialOverloading);
|
||||||
else
|
else
|
||||||
AddOverloadCandidate(FD, F.getPair(), Args, CandidateSet,
|
AddOverloadCandidate(FD, F.getPair(), Args, CandidateSet,
|
||||||
SuppressUserConversions, PartialOverloading);
|
SuppressUserConversions, PartialOverloading);
|
||||||
@ -6369,7 +6324,7 @@ void Sema::AddFunctionCandidates(const UnresolvedSetImpl &Fns,
|
|||||||
FunTmpl, F.getPair(),
|
FunTmpl, F.getPair(),
|
||||||
cast<CXXRecordDecl>(FunTmpl->getDeclContext()),
|
cast<CXXRecordDecl>(FunTmpl->getDeclContext()),
|
||||||
ExplicitTemplateArgs, Args[0]->getType(),
|
ExplicitTemplateArgs, Args[0]->getType(),
|
||||||
Args[0]->Classify(Context), Args[0], Args.slice(1), CandidateSet,
|
Args[0]->Classify(Context), Args.slice(1), CandidateSet,
|
||||||
SuppressUserConversions, PartialOverloading);
|
SuppressUserConversions, PartialOverloading);
|
||||||
else
|
else
|
||||||
AddTemplateOverloadCandidate(FunTmpl, F.getPair(),
|
AddTemplateOverloadCandidate(FunTmpl, F.getPair(),
|
||||||
@ -6385,7 +6340,6 @@ void Sema::AddFunctionCandidates(const UnresolvedSetImpl &Fns,
|
|||||||
void Sema::AddMethodCandidate(DeclAccessPair FoundDecl,
|
void Sema::AddMethodCandidate(DeclAccessPair FoundDecl,
|
||||||
QualType ObjectType,
|
QualType ObjectType,
|
||||||
Expr::Classification ObjectClassification,
|
Expr::Classification ObjectClassification,
|
||||||
Expr *ThisArg,
|
|
||||||
ArrayRef<Expr *> Args,
|
ArrayRef<Expr *> Args,
|
||||||
OverloadCandidateSet& CandidateSet,
|
OverloadCandidateSet& CandidateSet,
|
||||||
bool SuppressUserConversions) {
|
bool SuppressUserConversions) {
|
||||||
@ -6399,15 +6353,13 @@ void Sema::AddMethodCandidate(DeclAccessPair FoundDecl,
|
|||||||
assert(isa<CXXMethodDecl>(TD->getTemplatedDecl()) &&
|
assert(isa<CXXMethodDecl>(TD->getTemplatedDecl()) &&
|
||||||
"Expected a member function template");
|
"Expected a member function template");
|
||||||
AddMethodTemplateCandidate(TD, FoundDecl, ActingContext,
|
AddMethodTemplateCandidate(TD, FoundDecl, ActingContext,
|
||||||
/*ExplicitArgs*/ nullptr,
|
/*ExplicitArgs*/ nullptr, ObjectType,
|
||||||
ObjectType, ObjectClassification,
|
ObjectClassification, Args, CandidateSet,
|
||||||
ThisArg, Args, CandidateSet,
|
|
||||||
SuppressUserConversions);
|
SuppressUserConversions);
|
||||||
} else {
|
} else {
|
||||||
AddMethodCandidate(cast<CXXMethodDecl>(Decl), FoundDecl, ActingContext,
|
AddMethodCandidate(cast<CXXMethodDecl>(Decl), FoundDecl, ActingContext,
|
||||||
ObjectType, ObjectClassification,
|
ObjectType, ObjectClassification, Args, CandidateSet,
|
||||||
ThisArg, Args,
|
SuppressUserConversions);
|
||||||
CandidateSet, SuppressUserConversions);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -6422,7 +6374,7 @@ void
|
|||||||
Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl,
|
Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl,
|
||||||
CXXRecordDecl *ActingContext, QualType ObjectType,
|
CXXRecordDecl *ActingContext, QualType ObjectType,
|
||||||
Expr::Classification ObjectClassification,
|
Expr::Classification ObjectClassification,
|
||||||
Expr *ThisArg, ArrayRef<Expr *> Args,
|
ArrayRef<Expr *> Args,
|
||||||
OverloadCandidateSet &CandidateSet,
|
OverloadCandidateSet &CandidateSet,
|
||||||
bool SuppressUserConversions,
|
bool SuppressUserConversions,
|
||||||
bool PartialOverloading,
|
bool PartialOverloading,
|
||||||
@ -6544,9 +6496,6 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl,
|
|||||||
Candidate.DeductionFailure.Data = FailedAttr;
|
Candidate.DeductionFailure.Data = FailedAttr;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
initDiagnoseIfComplaint(*this, CandidateSet, Candidate, Method, Args,
|
|
||||||
/*MissingImplicitThis=*/!ThisArg, ThisArg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Add a C++ member function template as a candidate to the candidate
|
/// \brief Add a C++ member function template as a candidate to the candidate
|
||||||
@ -6559,7 +6508,6 @@ Sema::AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl,
|
|||||||
TemplateArgumentListInfo *ExplicitTemplateArgs,
|
TemplateArgumentListInfo *ExplicitTemplateArgs,
|
||||||
QualType ObjectType,
|
QualType ObjectType,
|
||||||
Expr::Classification ObjectClassification,
|
Expr::Classification ObjectClassification,
|
||||||
Expr *ThisArg,
|
|
||||||
ArrayRef<Expr *> Args,
|
ArrayRef<Expr *> Args,
|
||||||
OverloadCandidateSet& CandidateSet,
|
OverloadCandidateSet& CandidateSet,
|
||||||
bool SuppressUserConversions,
|
bool SuppressUserConversions,
|
||||||
@ -6613,9 +6561,9 @@ Sema::AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl,
|
|||||||
assert(isa<CXXMethodDecl>(Specialization) &&
|
assert(isa<CXXMethodDecl>(Specialization) &&
|
||||||
"Specialization is not a member function?");
|
"Specialization is not a member function?");
|
||||||
AddMethodCandidate(cast<CXXMethodDecl>(Specialization), FoundDecl,
|
AddMethodCandidate(cast<CXXMethodDecl>(Specialization), FoundDecl,
|
||||||
ActingContext, ObjectType, ObjectClassification,
|
ActingContext, ObjectType, ObjectClassification, Args,
|
||||||
/*ThisArg=*/ThisArg, Args, CandidateSet,
|
CandidateSet, SuppressUserConversions, PartialOverloading,
|
||||||
SuppressUserConversions, PartialOverloading, Conversions);
|
Conversions);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Add a C++ function template specialization as a candidate
|
/// \brief Add a C++ function template specialization as a candidate
|
||||||
@ -6942,8 +6890,6 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion,
|
|||||||
Candidate.DeductionFailure.Data = FailedAttr;
|
Candidate.DeductionFailure.Data = FailedAttr;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
initDiagnoseIfComplaint(*this, CandidateSet, Candidate, Conversion, None, false, From);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Adds a conversion function template specialization
|
/// \brief Adds a conversion function template specialization
|
||||||
@ -7096,8 +7042,6 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion,
|
|||||||
Candidate.DeductionFailure.Data = FailedAttr;
|
Candidate.DeductionFailure.Data = FailedAttr;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
initDiagnoseIfComplaint(*this, CandidateSet, Candidate, Conversion, None);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Add overload candidates for overloaded operators that are
|
/// \brief Add overload candidates for overloaded operators that are
|
||||||
@ -7146,7 +7090,7 @@ void Sema::AddMemberOperatorCandidates(OverloadedOperatorKind Op,
|
|||||||
Oper != OperEnd;
|
Oper != OperEnd;
|
||||||
++Oper)
|
++Oper)
|
||||||
AddMethodCandidate(Oper.getPair(), Args[0]->getType(),
|
AddMethodCandidate(Oper.getPair(), Args[0]->getType(),
|
||||||
Args[0]->Classify(Context), Args[0], Args.slice(1),
|
Args[0]->Classify(Context), Args.slice(1),
|
||||||
CandidateSet, /*SuppressUserConversions=*/false);
|
CandidateSet, /*SuppressUserConversions=*/false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -9178,17 +9122,6 @@ void Sema::diagnoseEquivalentInternalLinkageDeclarations(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool isCandidateUnavailableDueToDiagnoseIf(const OverloadCandidate &OC) {
|
|
||||||
ArrayRef<DiagnoseIfAttr *> Info = OC.getDiagnoseIfInfo();
|
|
||||||
if (!Info.empty() && Info[0]->isError())
|
|
||||||
return true;
|
|
||||||
|
|
||||||
assert(llvm::all_of(Info,
|
|
||||||
[](const DiagnoseIfAttr *A) { return !A->isError(); }) &&
|
|
||||||
"DiagnoseIf info shouldn't have mixed warnings and errors.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// \brief Computes the best viable function (C++ 13.3.3)
|
/// \brief Computes the best viable function (C++ 13.3.3)
|
||||||
/// within an overload candidate set.
|
/// within an overload candidate set.
|
||||||
///
|
///
|
||||||
@ -9267,19 +9200,13 @@ OverloadCandidateSet::BestViableFunction(Sema &S, SourceLocation Loc,
|
|||||||
// Best is the best viable function.
|
// Best is the best viable function.
|
||||||
if (Best->Function &&
|
if (Best->Function &&
|
||||||
(Best->Function->isDeleted() ||
|
(Best->Function->isDeleted() ||
|
||||||
S.isFunctionConsideredUnavailable(Best->Function) ||
|
S.isFunctionConsideredUnavailable(Best->Function)))
|
||||||
isCandidateUnavailableDueToDiagnoseIf(*Best)))
|
|
||||||
return OR_Deleted;
|
return OR_Deleted;
|
||||||
|
|
||||||
if (!EquivalentCands.empty())
|
if (!EquivalentCands.empty())
|
||||||
S.diagnoseEquivalentInternalLinkageDeclarations(Loc, Best->Function,
|
S.diagnoseEquivalentInternalLinkageDeclarations(Loc, Best->Function,
|
||||||
EquivalentCands);
|
EquivalentCands);
|
||||||
|
|
||||||
for (const auto *W : Best->getDiagnoseIfInfo()) {
|
|
||||||
assert(W->isWarning() && "Errors should've been caught earlier!");
|
|
||||||
S.emitDiagnoseIfDiagnostic(Loc, W);
|
|
||||||
}
|
|
||||||
|
|
||||||
return OR_Success;
|
return OR_Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -10162,14 +10089,6 @@ static void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand,
|
|||||||
MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl);
|
MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (isCandidateUnavailableDueToDiagnoseIf(*Cand)) {
|
|
||||||
auto *A = Cand->DiagnoseIfInfo.get<DiagnoseIfAttr *>();
|
|
||||||
assert(A->isError() && "Non-error diagnose_if disables a candidate?");
|
|
||||||
S.Diag(Cand->Function->getLocation(),
|
|
||||||
diag::note_ovl_candidate_disabled_by_function_cond_attr)
|
|
||||||
<< A->getCond()->getSourceRange() << A->getMessage();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// We don't really have anything else to say about viable candidates.
|
// We don't really have anything else to say about viable candidates.
|
||||||
S.NoteOverloadCandidate(Cand->FoundDecl, Fn);
|
S.NoteOverloadCandidate(Cand->FoundDecl, Fn);
|
||||||
@ -12113,6 +12032,10 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, UnaryOperatorKind Opc,
|
|||||||
if (CheckCallReturnType(FnDecl->getReturnType(), OpLoc, TheCall, FnDecl))
|
if (CheckCallReturnType(FnDecl->getReturnType(), OpLoc, TheCall, FnDecl))
|
||||||
return ExprError();
|
return ExprError();
|
||||||
|
|
||||||
|
if (CheckFunctionCall(FnDecl, TheCall,
|
||||||
|
FnDecl->getType()->castAs<FunctionProtoType>()))
|
||||||
|
return ExprError();
|
||||||
|
|
||||||
return MaybeBindToTemporary(TheCall);
|
return MaybeBindToTemporary(TheCall);
|
||||||
} else {
|
} else {
|
||||||
// We matched a built-in operator. Convert the arguments, then
|
// We matched a built-in operator. Convert the arguments, then
|
||||||
@ -12343,16 +12266,20 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
|
|||||||
return ExprError();
|
return ExprError();
|
||||||
|
|
||||||
ArrayRef<const Expr *> ArgsArray(Args, 2);
|
ArrayRef<const Expr *> ArgsArray(Args, 2);
|
||||||
|
const Expr *ImplicitThis = nullptr;
|
||||||
// Cut off the implicit 'this'.
|
// Cut off the implicit 'this'.
|
||||||
if (isa<CXXMethodDecl>(FnDecl))
|
if (isa<CXXMethodDecl>(FnDecl)) {
|
||||||
|
ImplicitThis = ArgsArray[0];
|
||||||
ArgsArray = ArgsArray.slice(1);
|
ArgsArray = ArgsArray.slice(1);
|
||||||
|
}
|
||||||
|
|
||||||
// Check for a self move.
|
// Check for a self move.
|
||||||
if (Op == OO_Equal)
|
if (Op == OO_Equal)
|
||||||
DiagnoseSelfMove(Args[0], Args[1], OpLoc);
|
DiagnoseSelfMove(Args[0], Args[1], OpLoc);
|
||||||
|
|
||||||
checkCall(FnDecl, nullptr, ArgsArray, isa<CXXMethodDecl>(FnDecl), OpLoc,
|
checkCall(FnDecl, nullptr, ImplicitThis, ArgsArray,
|
||||||
TheCall->getSourceRange(), VariadicDoesNotApply);
|
isa<CXXMethodDecl>(FnDecl), OpLoc, TheCall->getSourceRange(),
|
||||||
|
VariadicDoesNotApply);
|
||||||
|
|
||||||
return MaybeBindToTemporary(TheCall);
|
return MaybeBindToTemporary(TheCall);
|
||||||
} else {
|
} else {
|
||||||
@ -12561,6 +12488,10 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
|
|||||||
if (CheckCallReturnType(FnDecl->getReturnType(), LLoc, TheCall, FnDecl))
|
if (CheckCallReturnType(FnDecl->getReturnType(), LLoc, TheCall, FnDecl))
|
||||||
return ExprError();
|
return ExprError();
|
||||||
|
|
||||||
|
if (CheckFunctionCall(Method, TheCall,
|
||||||
|
Method->getType()->castAs<FunctionProtoType>()))
|
||||||
|
return ExprError();
|
||||||
|
|
||||||
return MaybeBindToTemporary(TheCall);
|
return MaybeBindToTemporary(TheCall);
|
||||||
} else {
|
} else {
|
||||||
// We matched a built-in operator. Convert the arguments, then
|
// We matched a built-in operator. Convert the arguments, then
|
||||||
@ -12727,16 +12658,6 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
|
|||||||
TemplateArgs = &TemplateArgsBuffer;
|
TemplateArgs = &TemplateArgsBuffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Poor-programmer's Lazy<Expr *>; isImplicitAccess requires stripping
|
|
||||||
// parens/casts, which would be nice to avoid potentially doing multiple
|
|
||||||
// times.
|
|
||||||
llvm::Optional<Expr *> UnresolvedBase;
|
|
||||||
auto GetUnresolvedBase = [&] {
|
|
||||||
if (!UnresolvedBase.hasValue())
|
|
||||||
UnresolvedBase =
|
|
||||||
UnresExpr->isImplicitAccess() ? nullptr : UnresExpr->getBase();
|
|
||||||
return *UnresolvedBase;
|
|
||||||
};
|
|
||||||
for (UnresolvedMemberExpr::decls_iterator I = UnresExpr->decls_begin(),
|
for (UnresolvedMemberExpr::decls_iterator I = UnresExpr->decls_begin(),
|
||||||
E = UnresExpr->decls_end(); I != E; ++I) {
|
E = UnresExpr->decls_end(); I != E; ++I) {
|
||||||
|
|
||||||
@ -12757,14 +12678,12 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
AddMethodCandidate(Method, I.getPair(), ActingDC, ObjectType,
|
AddMethodCandidate(Method, I.getPair(), ActingDC, ObjectType,
|
||||||
ObjectClassification,
|
ObjectClassification, Args, CandidateSet,
|
||||||
/*ThisArg=*/GetUnresolvedBase(), Args, CandidateSet,
|
|
||||||
/*SuppressUserConversions=*/false);
|
/*SuppressUserConversions=*/false);
|
||||||
} else {
|
} else {
|
||||||
AddMethodTemplateCandidate(
|
AddMethodTemplateCandidate(
|
||||||
cast<FunctionTemplateDecl>(Func), I.getPair(), ActingDC,
|
cast<FunctionTemplateDecl>(Func), I.getPair(), ActingDC,
|
||||||
TemplateArgs, ObjectType, ObjectClassification,
|
TemplateArgs, ObjectType, ObjectClassification, Args, CandidateSet,
|
||||||
/*ThisArg=*/GetUnresolvedBase(), Args, CandidateSet,
|
|
||||||
/*SuppressUsedConversions=*/false);
|
/*SuppressUsedConversions=*/false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -12882,16 +12801,6 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
|
|||||||
<< Attr->getCond()->getSourceRange() << Attr->getMessage();
|
<< Attr->getCond()->getSourceRange() << Attr->getMessage();
|
||||||
return ExprError();
|
return ExprError();
|
||||||
}
|
}
|
||||||
|
|
||||||
SmallVector<DiagnoseIfAttr *, 4> Nonfatal;
|
|
||||||
if (const DiagnoseIfAttr *Attr = checkArgDependentDiagnoseIf(
|
|
||||||
Method, Args, Nonfatal, false, MemE->getBase())) {
|
|
||||||
emitDiagnoseIfDiagnostic(MemE->getMemberLoc(), Attr);
|
|
||||||
return ExprError();
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const auto *Attr : Nonfatal)
|
|
||||||
emitDiagnoseIfDiagnostic(MemE->getMemberLoc(), Attr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((isa<CXXConstructorDecl>(CurContext) ||
|
if ((isa<CXXConstructorDecl>(CurContext) ||
|
||||||
@ -12970,9 +12879,8 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj,
|
|||||||
for (LookupResult::iterator Oper = R.begin(), OperEnd = R.end();
|
for (LookupResult::iterator Oper = R.begin(), OperEnd = R.end();
|
||||||
Oper != OperEnd; ++Oper) {
|
Oper != OperEnd; ++Oper) {
|
||||||
AddMethodCandidate(Oper.getPair(), Object.get()->getType(),
|
AddMethodCandidate(Oper.getPair(), Object.get()->getType(),
|
||||||
Object.get()->Classify(Context),
|
Object.get()->Classify(Context), Args, CandidateSet,
|
||||||
Object.get(), Args, CandidateSet,
|
/*SuppressUserConversions=*/false);
|
||||||
/*SuppressUserConversions=*/ false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// C++ [over.call.object]p2:
|
// C++ [over.call.object]p2:
|
||||||
@ -13247,8 +13155,7 @@ Sema::BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc,
|
|||||||
for (LookupResult::iterator Oper = R.begin(), OperEnd = R.end();
|
for (LookupResult::iterator Oper = R.begin(), OperEnd = R.end();
|
||||||
Oper != OperEnd; ++Oper) {
|
Oper != OperEnd; ++Oper) {
|
||||||
AddMethodCandidate(Oper.getPair(), Base->getType(), Base->Classify(Context),
|
AddMethodCandidate(Oper.getPair(), Base->getType(), Base->Classify(Context),
|
||||||
Base, None, CandidateSet,
|
None, CandidateSet, /*SuppressUserConversions=*/false);
|
||||||
/*SuppressUserConversions=*/false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HadMultipleCandidates = (CandidateSet.size() > 1);
|
bool HadMultipleCandidates = (CandidateSet.size() > 1);
|
||||||
@ -13322,7 +13229,11 @@ Sema::BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc,
|
|||||||
Base, ResultTy, VK, OpLoc, false);
|
Base, ResultTy, VK, OpLoc, false);
|
||||||
|
|
||||||
if (CheckCallReturnType(Method->getReturnType(), OpLoc, TheCall, Method))
|
if (CheckCallReturnType(Method->getReturnType(), OpLoc, TheCall, Method))
|
||||||
return ExprError();
|
return ExprError();
|
||||||
|
|
||||||
|
if (CheckFunctionCall(Method, TheCall,
|
||||||
|
Method->getType()->castAs<FunctionProtoType>()))
|
||||||
|
return ExprError();
|
||||||
|
|
||||||
return MaybeBindToTemporary(TheCall);
|
return MaybeBindToTemporary(TheCall);
|
||||||
}
|
}
|
||||||
|
@ -4996,8 +4996,12 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
|
|||||||
NamedDecl *Result = nullptr;
|
NamedDecl *Result = nullptr;
|
||||||
// FIXME: If the name is a dependent name, this lookup won't necessarily
|
// FIXME: If the name is a dependent name, this lookup won't necessarily
|
||||||
// find it. Does that ever matter?
|
// find it. Does that ever matter?
|
||||||
if (D->getDeclName()) {
|
if (auto Name = D->getDeclName()) {
|
||||||
DeclContext::lookup_result Found = ParentDC->lookup(D->getDeclName());
|
DeclarationNameInfo NameInfo(Name, D->getLocation());
|
||||||
|
Name = SubstDeclarationNameInfo(NameInfo, TemplateArgs).getName();
|
||||||
|
if (!Name)
|
||||||
|
return nullptr;
|
||||||
|
DeclContext::lookup_result Found = ParentDC->lookup(Name);
|
||||||
Result = findInstantiationOf(Context, D, Found.begin(), Found.end());
|
Result = findInstantiationOf(Context, D, Found.begin(), Found.end());
|
||||||
} else {
|
} else {
|
||||||
// Since we don't have a name for the entity we're looking for,
|
// Since we don't have a name for the entity we're looking for,
|
||||||
|
@ -8818,12 +8818,18 @@ TreeTransform<Derived>::TransformMemberExpr(MemberExpr *E) {
|
|||||||
// base (and therefore couldn't do the check) and a
|
// base (and therefore couldn't do the check) and a
|
||||||
// nested-name-qualifier (and therefore could do the lookup).
|
// nested-name-qualifier (and therefore could do the lookup).
|
||||||
NamedDecl *FirstQualifierInScope = nullptr;
|
NamedDecl *FirstQualifierInScope = nullptr;
|
||||||
|
DeclarationNameInfo MemberNameInfo = E->getMemberNameInfo();
|
||||||
|
if (MemberNameInfo.getName()) {
|
||||||
|
MemberNameInfo = getDerived().TransformDeclarationNameInfo(MemberNameInfo);
|
||||||
|
if (!MemberNameInfo.getName())
|
||||||
|
return ExprError();
|
||||||
|
}
|
||||||
|
|
||||||
return getDerived().RebuildMemberExpr(Base.get(), FakeOperatorLoc,
|
return getDerived().RebuildMemberExpr(Base.get(), FakeOperatorLoc,
|
||||||
E->isArrow(),
|
E->isArrow(),
|
||||||
QualifierLoc,
|
QualifierLoc,
|
||||||
TemplateKWLoc,
|
TemplateKWLoc,
|
||||||
E->getMemberNameInfo(),
|
MemberNameInfo,
|
||||||
Member,
|
Member,
|
||||||
FoundDecl,
|
FoundDecl,
|
||||||
(E->hasExplicitTemplateArgs()
|
(E->hasExplicitTemplateArgs()
|
||||||
|
@ -180,10 +180,6 @@ template <class ELFT> class ObjectFile : public ELFFileBase<ELFT> {
|
|||||||
// R_MIPS_GPREL16 / R_MIPS_GPREL32 relocations.
|
// R_MIPS_GPREL16 / R_MIPS_GPREL32 relocations.
|
||||||
uint32_t MipsGp0 = 0;
|
uint32_t MipsGp0 = 0;
|
||||||
|
|
||||||
// The number is the offset in the string table. It will be used as the
|
|
||||||
// st_name of the symbol.
|
|
||||||
std::vector<std::pair<const DefinedRegular<ELFT> *, unsigned>> KeptLocalSyms;
|
|
||||||
|
|
||||||
// Name of source file obtained from STT_FILE symbol value,
|
// Name of source file obtained from STT_FILE symbol value,
|
||||||
// or empty string if there is no such symbol in object file
|
// or empty string if there is no such symbol in object file
|
||||||
// symbol table.
|
// symbol table.
|
||||||
|
@ -246,7 +246,8 @@ void InputSection<ELFT>::copyRelocations(uint8_t *Buf, ArrayRef<RelTy> Rels) {
|
|||||||
if (Config->Rela)
|
if (Config->Rela)
|
||||||
P->r_addend = getAddend<ELFT>(Rel);
|
P->r_addend = getAddend<ELFT>(Rel);
|
||||||
P->r_offset = RelocatedSection->getOffset(Rel.r_offset);
|
P->r_offset = RelocatedSection->getOffset(Rel.r_offset);
|
||||||
P->setSymbolAndType(Body.DynsymIndex, Type, Config->Mips64EL);
|
P->setSymbolAndType(In<ELFT>::SymTab->getSymbolIndex(&Body), Type,
|
||||||
|
Config->Mips64EL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1065,22 +1065,21 @@ template <class ELFT> void SymbolTableSection<ELFT>::finalize() {
|
|||||||
this->OutSec->Info = this->Info = NumLocals + 1;
|
this->OutSec->Info = this->Info = NumLocals + 1;
|
||||||
this->OutSec->Entsize = this->Entsize;
|
this->OutSec->Entsize = this->Entsize;
|
||||||
|
|
||||||
if (Config->Relocatable) {
|
if (Config->Relocatable)
|
||||||
size_t I = NumLocals;
|
return;
|
||||||
for (const SymbolTableEntry &S : Symbols)
|
|
||||||
S.Symbol->DynsymIndex = ++I;
|
if (!StrTabSec.isDynamic()) {
|
||||||
|
auto GlobBegin = Symbols.begin() + NumLocals;
|
||||||
|
auto It = std::stable_partition(
|
||||||
|
GlobBegin, Symbols.end(), [](const SymbolTableEntry &S) {
|
||||||
|
return S.Symbol->symbol()->computeBinding() == STB_LOCAL;
|
||||||
|
});
|
||||||
|
// update sh_info with number of Global symbols output with computed
|
||||||
|
// binding of STB_LOCAL
|
||||||
|
this->OutSec->Info = this->Info = 1 + It - Symbols.begin();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!StrTabSec.isDynamic()) {
|
|
||||||
std::stable_sort(
|
|
||||||
Symbols.begin(), Symbols.end(),
|
|
||||||
[](const SymbolTableEntry &L, const SymbolTableEntry &R) {
|
|
||||||
return L.Symbol->symbol()->computeBinding() == STB_LOCAL &&
|
|
||||||
R.Symbol->symbol()->computeBinding() != STB_LOCAL;
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (In<ELFT>::GnuHashTab)
|
if (In<ELFT>::GnuHashTab)
|
||||||
// NB: It also sorts Symbols to meet the GNU hash table requirements.
|
// NB: It also sorts Symbols to meet the GNU hash table requirements.
|
||||||
In<ELFT>::GnuHashTab->addSymbols(Symbols);
|
In<ELFT>::GnuHashTab->addSymbols(Symbols);
|
||||||
@ -1094,10 +1093,25 @@ template <class ELFT> void SymbolTableSection<ELFT>::finalize() {
|
|||||||
S.Symbol->DynsymIndex = ++I;
|
S.Symbol->DynsymIndex = ++I;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class ELFT> void SymbolTableSection<ELFT>::addSymbol(SymbolBody *B) {
|
template <class ELFT> void SymbolTableSection<ELFT>::addGlobal(SymbolBody *B) {
|
||||||
Symbols.push_back({B, StrTabSec.addString(B->getName(), false)});
|
Symbols.push_back({B, StrTabSec.addString(B->getName(), false)});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <class ELFT> void SymbolTableSection<ELFT>::addLocal(SymbolBody *B) {
|
||||||
|
assert(!StrTabSec.isDynamic());
|
||||||
|
++NumLocals;
|
||||||
|
Symbols.push_back({B, StrTabSec.addString(B->getName())});
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class ELFT>
|
||||||
|
size_t SymbolTableSection<ELFT>::getSymbolIndex(SymbolBody *Body) {
|
||||||
|
auto I = llvm::find_if(
|
||||||
|
Symbols, [&](const SymbolTableEntry &E) { return E.Symbol == Body; });
|
||||||
|
if (I == Symbols.end())
|
||||||
|
return 0;
|
||||||
|
return I - Symbols.begin() + 1;
|
||||||
|
}
|
||||||
|
|
||||||
template <class ELFT> void SymbolTableSection<ELFT>::writeTo(uint8_t *Buf) {
|
template <class ELFT> void SymbolTableSection<ELFT>::writeTo(uint8_t *Buf) {
|
||||||
Buf += sizeof(Elf_Sym);
|
Buf += sizeof(Elf_Sym);
|
||||||
|
|
||||||
@ -1113,26 +1127,24 @@ template <class ELFT>
|
|||||||
void SymbolTableSection<ELFT>::writeLocalSymbols(uint8_t *&Buf) {
|
void SymbolTableSection<ELFT>::writeLocalSymbols(uint8_t *&Buf) {
|
||||||
// Iterate over all input object files to copy their local symbols
|
// Iterate over all input object files to copy their local symbols
|
||||||
// to the output symbol table pointed by Buf.
|
// to the output symbol table pointed by Buf.
|
||||||
for (ObjectFile<ELFT> *File : Symtab<ELFT>::X->getObjectFiles()) {
|
|
||||||
for (const std::pair<const DefinedRegular<ELFT> *, size_t> &P :
|
|
||||||
File->KeptLocalSyms) {
|
|
||||||
const DefinedRegular<ELFT> &Body = *P.first;
|
|
||||||
InputSectionBase<ELFT> *Section = Body.Section;
|
|
||||||
auto *ESym = reinterpret_cast<Elf_Sym *>(Buf);
|
|
||||||
|
|
||||||
if (!Section) {
|
for (auto I = Symbols.begin(); I != Symbols.begin() + NumLocals; ++I) {
|
||||||
ESym->st_shndx = SHN_ABS;
|
const DefinedRegular<ELFT> &Body = *cast<DefinedRegular<ELFT>>(I->Symbol);
|
||||||
ESym->st_value = Body.Value;
|
InputSectionBase<ELFT> *Section = Body.Section;
|
||||||
} else {
|
auto *ESym = reinterpret_cast<Elf_Sym *>(Buf);
|
||||||
const OutputSectionBase *OutSec = Section->OutSec;
|
|
||||||
ESym->st_shndx = OutSec->SectionIndex;
|
if (!Section) {
|
||||||
ESym->st_value = OutSec->Addr + Section->getOffset(Body);
|
ESym->st_shndx = SHN_ABS;
|
||||||
}
|
ESym->st_value = Body.Value;
|
||||||
ESym->st_name = P.second;
|
} else {
|
||||||
ESym->st_size = Body.template getSize<ELFT>();
|
const OutputSectionBase *OutSec = Section->OutSec;
|
||||||
ESym->setBindingAndType(STB_LOCAL, Body.Type);
|
ESym->st_shndx = OutSec->SectionIndex;
|
||||||
Buf += sizeof(*ESym);
|
ESym->st_value = OutSec->Addr + Section->getOffset(Body);
|
||||||
}
|
}
|
||||||
|
ESym->st_name = I->StrTabOffset;
|
||||||
|
ESym->st_size = Body.template getSize<ELFT>();
|
||||||
|
ESym->setBindingAndType(STB_LOCAL, Body.Type);
|
||||||
|
Buf += sizeof(*ESym);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1141,7 +1153,9 @@ void SymbolTableSection<ELFT>::writeGlobalSymbols(uint8_t *Buf) {
|
|||||||
// Write the internal symbol table contents to the output symbol table
|
// Write the internal symbol table contents to the output symbol table
|
||||||
// pointed by Buf.
|
// pointed by Buf.
|
||||||
auto *ESym = reinterpret_cast<Elf_Sym *>(Buf);
|
auto *ESym = reinterpret_cast<Elf_Sym *>(Buf);
|
||||||
for (const SymbolTableEntry &S : Symbols) {
|
|
||||||
|
for (auto I = Symbols.begin() + NumLocals; I != Symbols.end(); ++I) {
|
||||||
|
const SymbolTableEntry &S = *I;
|
||||||
SymbolBody *Body = S.Symbol;
|
SymbolBody *Body = S.Symbol;
|
||||||
size_t StrOff = S.StrTabOffset;
|
size_t StrOff = S.StrTabOffset;
|
||||||
|
|
||||||
|
@ -366,23 +366,26 @@ class SymbolTableSection final : public SyntheticSection<ELFT> {
|
|||||||
void finalize() override;
|
void finalize() override;
|
||||||
void writeTo(uint8_t *Buf) override;
|
void writeTo(uint8_t *Buf) override;
|
||||||
size_t getSize() const override { return getNumSymbols() * sizeof(Elf_Sym); }
|
size_t getSize() const override { return getNumSymbols() * sizeof(Elf_Sym); }
|
||||||
void addSymbol(SymbolBody *Body);
|
void addGlobal(SymbolBody *Body);
|
||||||
|
void addLocal(SymbolBody *Body);
|
||||||
StringTableSection<ELFT> &getStrTabSec() const { return StrTabSec; }
|
StringTableSection<ELFT> &getStrTabSec() const { return StrTabSec; }
|
||||||
unsigned getNumSymbols() const { return NumLocals + Symbols.size() + 1; }
|
unsigned getNumSymbols() const { return Symbols.size() + 1; }
|
||||||
|
size_t getSymbolIndex(SymbolBody *Body);
|
||||||
|
|
||||||
ArrayRef<SymbolTableEntry> getSymbols() const { return Symbols; }
|
ArrayRef<SymbolTableEntry> getSymbols() const { return Symbols; }
|
||||||
|
|
||||||
static const OutputSectionBase *getOutputSection(SymbolBody *Sym);
|
static const OutputSectionBase *getOutputSection(SymbolBody *Sym);
|
||||||
|
|
||||||
unsigned NumLocals = 0;
|
|
||||||
StringTableSection<ELFT> &StrTabSec;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void writeLocalSymbols(uint8_t *&Buf);
|
void writeLocalSymbols(uint8_t *&Buf);
|
||||||
void writeGlobalSymbols(uint8_t *Buf);
|
void writeGlobalSymbols(uint8_t *Buf);
|
||||||
|
|
||||||
// A vector of symbols and their string table offsets.
|
// A vector of symbols and their string table offsets.
|
||||||
std::vector<SymbolTableEntry> Symbols;
|
std::vector<SymbolTableEntry> Symbols;
|
||||||
|
|
||||||
|
StringTableSection<ELFT> &StrTabSec;
|
||||||
|
|
||||||
|
unsigned NumLocals = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Outputs GNU Hash section. For detailed explanation see:
|
// Outputs GNU Hash section. For detailed explanation see:
|
||||||
|
@ -455,11 +455,7 @@ template <class ELFT> void Writer<ELFT>::copyLocalSymbols() {
|
|||||||
InputSectionBase<ELFT> *Sec = DR->Section;
|
InputSectionBase<ELFT> *Sec = DR->Section;
|
||||||
if (!shouldKeepInSymtab<ELFT>(Sec, B->getName(), *B))
|
if (!shouldKeepInSymtab<ELFT>(Sec, B->getName(), *B))
|
||||||
continue;
|
continue;
|
||||||
++In<ELFT>::SymTab->NumLocals;
|
In<ELFT>::SymTab->addLocal(B);
|
||||||
if (Config->Relocatable)
|
|
||||||
B->DynsymIndex = In<ELFT>::SymTab->NumLocals;
|
|
||||||
F->KeptLocalSyms.push_back(std::make_pair(
|
|
||||||
DR, In<ELFT>::SymTab->StrTabSec.addString(B->getName())));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1024,10 +1020,10 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
|
|||||||
if (!includeInSymtab<ELFT>(*Body))
|
if (!includeInSymtab<ELFT>(*Body))
|
||||||
continue;
|
continue;
|
||||||
if (In<ELFT>::SymTab)
|
if (In<ELFT>::SymTab)
|
||||||
In<ELFT>::SymTab->addSymbol(Body);
|
In<ELFT>::SymTab->addGlobal(Body);
|
||||||
|
|
||||||
if (In<ELFT>::DynSymTab && S->includeInDynsym()) {
|
if (In<ELFT>::DynSymTab && S->includeInDynsym()) {
|
||||||
In<ELFT>::DynSymTab->addSymbol(Body);
|
In<ELFT>::DynSymTab->addGlobal(Body);
|
||||||
if (auto *SS = dyn_cast<SharedSymbol<ELFT>>(Body))
|
if (auto *SS = dyn_cast<SharedSymbol<ELFT>>(Body))
|
||||||
if (SS->file()->isNeeded())
|
if (SS->file()->isNeeded())
|
||||||
In<ELFT>::VerNeed->addSymbol(SS);
|
In<ELFT>::VerNeed->addSymbol(SS);
|
||||||
|
@ -8,4 +8,4 @@
|
|||||||
|
|
||||||
#define CLANG_VENDOR "FreeBSD "
|
#define CLANG_VENDOR "FreeBSD "
|
||||||
|
|
||||||
#define SVN_REVISION "293443"
|
#define SVN_REVISION "293807"
|
||||||
|
@ -4,5 +4,5 @@
|
|||||||
#define LLD_VERSION_STRING "4.0.0"
|
#define LLD_VERSION_STRING "4.0.0"
|
||||||
#define LLD_VERSION_MAJOR 4
|
#define LLD_VERSION_MAJOR 4
|
||||||
#define LLD_VERSION_MINOR 0
|
#define LLD_VERSION_MINOR 0
|
||||||
#define LLD_REVISION_STRING "293443"
|
#define LLD_REVISION_STRING "293807"
|
||||||
#define LLD_REPOSITORY_STRING "FreeBSD"
|
#define LLD_REPOSITORY_STRING "FreeBSD"
|
||||||
|
Loading…
Reference in New Issue
Block a user