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
|
||||
|
||||
template <class _Fp>
|
||||
inline _LIBCPP_INLINE_VISIBILITY
|
||||
void
|
||||
__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.
|
||||
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
|
||||
//===------------------------------------------------------------------===//
|
||||
|
@ -305,7 +305,7 @@ class SelectionDAGISel : public MachineFunctionPass {
|
||||
std::vector<unsigned> OpcodeOffset;
|
||||
|
||||
void UpdateChains(SDNode *NodeToMatch, SDValue InputChain,
|
||||
const SmallVectorImpl<SDNode *> &ChainNodesMatched,
|
||||
SmallVectorImpl<SDNode *> &ChainNodesMatched,
|
||||
bool isMorphNodeTo);
|
||||
};
|
||||
|
||||
|
@ -567,6 +567,15 @@ void AsmPrinter::EmitGlobalVariable(const GlobalVariable *GV) {
|
||||
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
|
||||
/// function.
|
||||
void AsmPrinter::EmitFunctionHeader() {
|
||||
|
@ -484,7 +484,7 @@ void DIEInteger::print(raw_ostream &O) const {
|
||||
/// EmitValue - Emit expression value.
|
||||
///
|
||||
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.
|
||||
|
@ -174,7 +174,7 @@ static bool isDeInterleaveMask(ArrayRef<int> Mask, unsigned &Factor,
|
||||
/// 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>
|
||||
static bool isReInterleaveMask(ArrayRef<int> Mask, unsigned &Factor,
|
||||
unsigned MaxFactor) {
|
||||
unsigned MaxFactor, unsigned OpNumElts) {
|
||||
unsigned NumElts = Mask.size();
|
||||
if (NumElts < 4)
|
||||
return false;
|
||||
@ -246,6 +246,9 @@ static bool isReInterleaveMask(ArrayRef<int> Mask, unsigned &Factor,
|
||||
|
||||
if (StartMask < 0)
|
||||
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.
|
||||
@ -406,7 +409,8 @@ bool InterleavedAccess::lowerInterleavedStore(
|
||||
|
||||
// Check if the shufflevector is RE-interleave shuffle.
|
||||
unsigned Factor;
|
||||
if (!isReInterleaveMask(SVI->getShuffleMask(), Factor, MaxFactor))
|
||||
unsigned OpNumElts = SVI->getOperand(0)->getType()->getVectorNumElements();
|
||||
if (!isReInterleaveMask(SVI->getShuffleMask(), Factor, MaxFactor, OpNumElts))
|
||||
return false;
|
||||
|
||||
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.
|
||||
void SelectionDAGISel::UpdateChains(
|
||||
SDNode *NodeToMatch, SDValue InputChain,
|
||||
const SmallVectorImpl<SDNode *> &ChainNodesMatched, bool isMorphNodeTo) {
|
||||
SmallVectorImpl<SDNode *> &ChainNodesMatched, bool isMorphNodeTo) {
|
||||
SmallVector<SDNode*, 4> NowDeadNodes;
|
||||
|
||||
// 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.
|
||||
for (unsigned i = 0, e = ChainNodesMatched.size(); i != e; ++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 &&
|
||||
"Deleted node left in chain");
|
||||
|
||||
@ -2272,6 +2277,11 @@ void SelectionDAGISel::UpdateChains(
|
||||
if (ChainVal.getValueType() == MVT::Glue)
|
||||
ChainVal = ChainVal.getValue(ChainVal->getNumValues()-2);
|
||||
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);
|
||||
|
||||
// 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")
|
||||
return true;
|
||||
|
||||
if (SegName == "__DATA" && SecName == "__nl_symbol_ptr")
|
||||
if (SegName == "__DATA" && (SecName == "__nl_symbol_ptr" ||
|
||||
SecName == "__thread_ptr"))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
|
@ -413,6 +413,7 @@ class MipsAsmParser : public MCTargetAsmParser {
|
||||
Match_RequiresDifferentOperands,
|
||||
Match_RequiresNoZeroRegister,
|
||||
Match_RequiresSameSrcAndDst,
|
||||
Match_NoFCCRegisterForCurrentISA,
|
||||
Match_NonZeroOperandForSync,
|
||||
#define GET_OPERAND_DIAGNOSTIC_TYPES
|
||||
#include "MipsGenAsmMatcher.inc"
|
||||
@ -1461,8 +1462,6 @@ class MipsOperand : public MCParsedAsmOperand {
|
||||
bool isFCCAsmReg() const {
|
||||
if (!(isRegIdx() && RegIdx.Kind & RegKind_FCC))
|
||||
return false;
|
||||
if (!AsmParser.hasEightFccRegisters())
|
||||
return RegIdx.Index == 0;
|
||||
return RegIdx.Index <= 7;
|
||||
}
|
||||
bool isACCAsmReg() const {
|
||||
@ -4053,6 +4052,7 @@ MipsAsmParser::checkEarlyTargetMatchPredicate(MCInst &Inst,
|
||||
return Match_RequiresSameSrcAndDst;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned MipsAsmParser::checkTargetMatchPredicate(MCInst &Inst) {
|
||||
switch (Inst.getOpcode()) {
|
||||
// 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())
|
||||
return Match_RequiresDifferentOperands;
|
||||
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,
|
||||
@ -4191,6 +4197,9 @@ bool MipsAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
|
||||
return Error(IDLoc, "invalid operand ($zero) for instruction");
|
||||
case Match_RequiresSameSrcAndDst:
|
||||
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:
|
||||
return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), "expected '0'");
|
||||
case Match_UImm1_0:
|
||||
|
@ -123,7 +123,9 @@ namespace MipsII {
|
||||
HasForbiddenSlot = 1 << 5,
|
||||
/// IsPCRelativeLoad - A Load instruction with implicit source 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;
|
||||
|
||||
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>,
|
||||
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>,
|
||||
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>,
|
||||
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 {
|
||||
bits<5> fs;
|
||||
bits<5> ft;
|
||||
bits<3> fcc;
|
||||
bits<4> cond;
|
||||
|
||||
bits<32> Inst;
|
||||
@ -773,13 +774,17 @@ class CEQS_FM_MM<bits<2> fmt> : MMArch {
|
||||
let Inst{31-26} = 0x15;
|
||||
let Inst{25-21} = ft;
|
||||
let Inst{20-16} = fs;
|
||||
let Inst{15-13} = 0x0; // cc
|
||||
let Inst{15-13} = fcc;
|
||||
let Inst{12} = 0;
|
||||
let Inst{11-10} = fmt;
|
||||
let Inst{9-6} = cond;
|
||||
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 {
|
||||
bits<16> offset;
|
||||
|
||||
|
@ -1037,6 +1037,22 @@ void MipsAsmPrinter::PrintDebugValueComment(const MachineInstr *MI,
|
||||
// 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
|
||||
// is NaCl.
|
||||
void MipsAsmPrinter::NaClAlignIndirectJumpTargets(MachineFunction &MF) {
|
||||
|
@ -140,6 +140,7 @@ class LLVM_LIBRARY_VISIBILITY MipsAsmPrinter : public AsmPrinter {
|
||||
void EmitStartOfAsmFile(Module &M) override;
|
||||
void EmitEndOfAsmFile(Module &M) override;
|
||||
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);
|
||||
emitInst(Mips::ADDiu, RegWithZero).addReg(Mips::ZERO).addImm(0);
|
||||
emitInst(Mips::ADDiu, RegWithOne).addReg(Mips::ZERO).addImm(1);
|
||||
emitInst(Opc).addReg(LeftReg).addReg(RightReg).addReg(
|
||||
Mips::FCC0, RegState::ImplicitDefine);
|
||||
emitInst(Opc).addReg(Mips::FCC0, RegState::Define).addReg(LeftReg)
|
||||
.addReg(RightReg);
|
||||
emitInst(CondMovOpc, ResultReg)
|
||||
.addReg(RegWithOne)
|
||||
.addReg(Mips::FCC0)
|
||||
|
@ -219,6 +219,7 @@ class BC1F_FT<string opstr, DAGOperand opnd, InstrItinClass Itin,
|
||||
let isTerminator = 1;
|
||||
let hasDelaySlot = DelaySlot;
|
||||
let Defs = [AT];
|
||||
let hasFCCRegOperand = 1;
|
||||
}
|
||||
|
||||
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 {
|
||||
let Defs = [FCC0];
|
||||
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,
|
||||
InstrItinClass itin> :
|
||||
InstSE<(outs), (ins RC:$fs, RC:$ft),
|
||||
!strconcat("c.", CondStr, ".", Typestr, "\t$fs, $ft"), [], itin,
|
||||
FrmFR>, HARDFLOAT;
|
||||
InstSE<(outs FCCRegsOpnd:$fcc), (ins RC:$fs, RC:$ft),
|
||||
!strconcat("c.", CondStr, ".", Typestr, "\t$fcc, $fs, $ft"), [], itin,
|
||||
FrmFR>, HARDFLOAT {
|
||||
let isCompare = 1;
|
||||
let hasFCCRegOperand = 1;
|
||||
}
|
||||
|
||||
|
||||
multiclass C_COND_M<string TypeStr, RegisterOperand RC, bits<5> fmt,
|
||||
InstrItinClass itin> {
|
||||
def C_F_#NAME : C_COND_FT<"f", TypeStr, RC, itin>, C_COND_FM<fmt, 0>;
|
||||
def C_UN_#NAME : C_COND_FT<"un", TypeStr, RC, itin>, C_COND_FM<fmt, 1>;
|
||||
def C_EQ_#NAME : C_COND_FT<"eq", TypeStr, RC, itin>, C_COND_FM<fmt, 2>;
|
||||
def C_UEQ_#NAME : C_COND_FT<"ueq", TypeStr, RC, itin>, C_COND_FM<fmt, 3>;
|
||||
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_OLE_#NAME : C_COND_FT<"ole", TypeStr, RC, itin>, C_COND_FM<fmt, 6>;
|
||||
def C_ULE_#NAME : C_COND_FT<"ule", TypeStr, RC, itin>, C_COND_FM<fmt, 7>;
|
||||
def C_SF_#NAME : C_COND_FT<"sf", TypeStr, RC, itin>, C_COND_FM<fmt, 8>;
|
||||
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_NGL_#NAME : C_COND_FT<"ngl", TypeStr, RC, itin>, C_COND_FM<fmt, 11>;
|
||||
def C_LT_#NAME : C_COND_FT<"lt", TypeStr, RC, itin>, C_COND_FM<fmt, 12>;
|
||||
def C_NGE_#NAME : C_COND_FT<"nge", TypeStr, RC, itin>, C_COND_FM<fmt, 13>;
|
||||
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_F_#NAME : MMRel, C_COND_FT<"f", TypeStr, RC, itin>,
|
||||
C_COND_FM<fmt, 0> {
|
||||
let BaseOpcode = "c.f."#NAME;
|
||||
let isCommutable = 1;
|
||||
}
|
||||
def C_UN_#NAME : MMRel, C_COND_FT<"un", TypeStr, RC, itin>,
|
||||
C_COND_FM<fmt, 1> {
|
||||
let BaseOpcode = "c.un."#NAME;
|
||||
let isCommutable = 1;
|
||||
}
|
||||
def C_EQ_#NAME : MMRel, C_COND_FT<"eq", TypeStr, RC, itin>,
|
||||
C_COND_FM<fmt, 2> {
|
||||
let BaseOpcode = "c.eq."#NAME;
|
||||
let isCommutable = 1;
|
||||
}
|
||||
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 D32 : C_COND_M<"d", AFGR64Opnd, 17, II_C_CC_D>, ISA_MIPS1_NOT_32R6_64R6,
|
||||
FGR_32;
|
||||
let DecoderNamespace = "Mips64" in
|
||||
defm D64 : C_COND_M<"d", FGR64Opnd, 17, II_C_CC_D>, ISA_MIPS1_NOT_32R6_64R6,
|
||||
FGR_64;
|
||||
|
||||
}
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Floating Point Instructions
|
||||
//===----------------------------------------------------------------------===//
|
||||
@ -549,13 +615,29 @@ def BC1TL : MMRel, BC1F_FT<"bc1tl", brtarget, II_BC1TL, MIPS_BRANCH_T, 0>,
|
||||
/// Floating Point Compare
|
||||
let AdditionalPredicates = [NotInMicroMips] in {
|
||||
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>,
|
||||
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
|
||||
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
|
||||
@ -602,15 +684,6 @@ def PseudoTRUNC_W_D : MipsAsmPseudoInst<(outs FGR32Opnd:$fd),
|
||||
//===----------------------------------------------------------------------===//
|
||||
// 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
|
||||
<"s.s $fd, $addr", (SWC1 FGR32Opnd:$fd, mem_simm16:$addr), 0>,
|
||||
ISA_MIPS2, HARDFLOAT;
|
||||
@ -630,6 +703,80 @@ def : MipsInstAlias
|
||||
def : MipsInstAlias
|
||||
<"l.d $fd, $addr", (LDC164 FGR64Opnd:$fd, mem_simm16:$addr), 0>,
|
||||
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
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@ -101,12 +101,15 @@ class MipsInst<dag outs, dag ins, string asmstr, list<dag> pattern,
|
||||
bit IsPCRelativeLoad = 0; // Load instruction with implicit source register
|
||||
// ($pc) and with explicit offset and destination
|
||||
// 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{4} = isCTI;
|
||||
let TSFlags{5} = hasForbiddenSlot;
|
||||
let TSFlags{6} = IsPCRelativeLoad;
|
||||
let TSFlags{7} = hasFCCRegOperand;
|
||||
|
||||
let DecoderNamespace = "Mips";
|
||||
|
||||
@ -829,6 +832,7 @@ class BC1F_FM<bit nd, bit tf> : StdArch {
|
||||
class CEQS_FM<bits<5> fmt> : StdArch {
|
||||
bits<5> fs;
|
||||
bits<5> ft;
|
||||
bits<3> fcc;
|
||||
bits<4> cond;
|
||||
|
||||
bits<32> Inst;
|
||||
@ -837,7 +841,7 @@ class CEQS_FM<bits<5> fmt> : StdArch {
|
||||
let Inst{25-21} = fmt;
|
||||
let Inst{20-16} = ft;
|
||||
let Inst{15-11} = fs;
|
||||
let Inst{10-8} = 0; // cc
|
||||
let Inst{10-8} = fcc;
|
||||
let Inst{7-4} = 0x3;
|
||||
let Inst{3-0} = cond;
|
||||
}
|
||||
|
@ -148,3 +148,11 @@ MCSection *MipsTargetObjectFile::getSectionForConstant(const DataLayout &DL,
|
||||
// Otherwise, we work the same as ELF.
|
||||
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,
|
||||
const Constant *C,
|
||||
unsigned &Align) const override;
|
||||
/// Describe a TLS variable address within debug info.
|
||||
const MCExpr *getDebugThreadLocalSymbol(const MCSymbol *Sym) const override;
|
||||
};
|
||||
} // end namespace llvm
|
||||
|
||||
|
@ -1508,8 +1508,14 @@ def DCBTST : DCB_Form_hint<246, (outs), (ins u5imm:$TH, memrr:$dst),
|
||||
PPC970_DGroup_Single;
|
||||
} // 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),
|
||||
"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),
|
||||
(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),
|
||||
"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
|
||||
// on a 32-bit target.
|
||||
let hasSideEffects = 1, usesCustomInserter = 1 in
|
||||
|
@ -118,6 +118,8 @@ def IIC_SprTLBIE : InstrItinClass;
|
||||
def IIC_SprABORT : InstrItinClass;
|
||||
def IIC_SprMSGSYNC : InstrItinClass;
|
||||
def IIC_SprSTOP : InstrItinClass;
|
||||
def IIC_SprMFPMR : InstrItinClass;
|
||||
def IIC_SprMTPMR : InstrItinClass;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Processor instruction itineraries.
|
||||
|
@ -249,6 +249,10 @@ def PPCE500mcItineraries : ProcessorItineraries<
|
||||
InstrStage<5, [E500_SFX0]>],
|
||||
[8, 1],
|
||||
[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>,
|
||||
InstrStage<4, [E500_SFX0]>],
|
||||
[7, 1], // Latency = 4, Repeat rate = 4
|
||||
@ -257,6 +261,10 @@ def PPCE500mcItineraries : ProcessorItineraries<
|
||||
InstrStage<1, [E500_SFX0, E500_SFX1]>],
|
||||
[4, 1], // Latency = 1, Repeat rate = 1
|
||||
[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>,
|
||||
InstrStage<4, [E500_SFX0]>],
|
||||
[7, 1], // Latency = 4, Repeat rate = 4
|
||||
|
@ -313,20 +313,24 @@ def PPCE5500Itineraries : ProcessorItineraries<
|
||||
InstrStage<5, [E5500_CFX_0]>],
|
||||
[9, 2], // Latency = 5, Repeat rate = 5
|
||||
[E5500_GPR_Bypass, E5500_CR_Bypass]>,
|
||||
InstrItinData<IIC_SprMFMSR, [InstrStage<1, [E5500_DIS0, E5500_DIS1], 0>,
|
||||
InstrStage<4, [E5500_SFX0]>],
|
||||
InstrItinData<IIC_SprMFPMR, [InstrStage<1, [E5500_DIS0, E5500_DIS1], 0>,
|
||||
InstrStage<4, [E5500_CFX_0]>],
|
||||
[8, 2], // Latency = 4, Repeat rate = 4
|
||||
[E5500_GPR_Bypass, E5500_GPR_Bypass]>,
|
||||
InstrItinData<IIC_SprMFSPR, [InstrStage<1, [E5500_DIS0, E5500_DIS1], 0>,
|
||||
InstrStage<1, [E5500_CFX_0]>],
|
||||
[5], // Latency = 1, Repeat rate = 1
|
||||
[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>,
|
||||
InstrStage<4, [E5500_CFX_0]>],
|
||||
[8, 2], // Latency = 4, Repeat rate = 4
|
||||
[NoBypass, E5500_GPR_Bypass]>,
|
||||
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
|
||||
[E5500_GPR_Bypass]>,
|
||||
InstrItinData<IIC_FPGeneral, [InstrStage<1, [E5500_DIS0, E5500_DIS1], 0>,
|
||||
|
@ -884,6 +884,10 @@ static Instruction *transformToIndexedCompare(GEPOperator *GEPLHS, Value *RHS,
|
||||
if (!GEPLHS->hasAllConstantIndices())
|
||||
return nullptr;
|
||||
|
||||
// Make sure the pointers have the same type.
|
||||
if (GEPLHS->getType() != RHS->getType())
|
||||
return nullptr;
|
||||
|
||||
Value *PtrBase, *Index;
|
||||
std::tie(PtrBase, Index) = getAsConstantIndexedAddress(GEPLHS, DL);
|
||||
|
||||
|
@ -502,7 +502,8 @@ static Instruction *combineLoadToOperationType(InstCombiner &IC, LoadInst &LI) {
|
||||
!DL.isNonIntegralPointerType(Ty)) {
|
||||
if (all_of(LI.users(), [&LI](User *U) {
|
||||
auto *SI = dyn_cast<StoreInst>(U);
|
||||
return SI && SI->getPointerOperand() != &LI;
|
||||
return SI && SI->getPointerOperand() != &LI &&
|
||||
!SI->getPointerOperand()->isSwiftError();
|
||||
})) {
|
||||
LoadInst *NewLoad = combineLoadToNewType(
|
||||
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
|
||||
// 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);
|
||||
|
||||
// If this function only has direct calls that we can see, we can track its
|
||||
|
@ -3827,12 +3827,12 @@ class AttributedType : public Type, public llvm::FoldingSetNode {
|
||||
|
||||
friend class ASTContext; // creates these
|
||||
|
||||
AttributedType(QualType canon, Kind attrKind,
|
||||
QualType modified, QualType equivalent)
|
||||
: Type(Attributed, canon, canon->isDependentType(),
|
||||
canon->isInstantiationDependentType(),
|
||||
canon->isVariablyModifiedType(),
|
||||
canon->containsUnexpandedParameterPack()),
|
||||
AttributedType(QualType canon, Kind attrKind, QualType modified,
|
||||
QualType equivalent)
|
||||
: Type(Attributed, canon, equivalent->isDependentType(),
|
||||
equivalent->isInstantiationDependentType(),
|
||||
equivalent->isVariablyModifiedType(),
|
||||
equivalent->containsUnexpandedParameterPack()),
|
||||
ModifiedType(modified), EquivalentType(equivalent) {
|
||||
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 "
|
||||
"pass_object_size attribute">;
|
||||
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<
|
||||
"candidate disabled: %0">;
|
||||
def note_ovl_candidate_disabled_by_extension : Note<
|
||||
|
@ -675,26 +675,6 @@ namespace clang {
|
||||
/// to be used while performing partial ordering of function templates.
|
||||
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 {
|
||||
DeductionFailureInfo DeductionFailure;
|
||||
|
||||
@ -759,9 +739,8 @@ namespace clang {
|
||||
SmallVector<OverloadCandidate, 16> Candidates;
|
||||
llvm::SmallPtrSet<Decl *, 16> Functions;
|
||||
|
||||
// Allocator for ConversionSequenceLists and DiagnoseIfAttr* arrays.
|
||||
// We store the first few of each of these inline to avoid allocation for
|
||||
// small sets.
|
||||
// Allocator for ConversionSequenceLists. We store the first few of these
|
||||
// inline to avoid allocation for small sets.
|
||||
llvm::BumpPtrAllocator SlabAllocator;
|
||||
|
||||
SourceLocation Loc;
|
||||
@ -776,6 +755,8 @@ namespace clang {
|
||||
/// from the slab allocator.
|
||||
/// FIXME: It would probably be nice to have a SmallBumpPtrAllocator
|
||||
/// instead.
|
||||
/// FIXME: Now that this only allocates ImplicitConversionSequences, do we
|
||||
/// want to un-generalize this?
|
||||
template <typename T>
|
||||
T *slabAllocate(unsigned N) {
|
||||
// It's simpler if this doesn't need to consider alignment.
|
||||
@ -809,11 +790,6 @@ namespace clang {
|
||||
SourceLocation getLocation() const { return Loc; }
|
||||
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
|
||||
/// overload set.
|
||||
bool isNewCandidate(Decl *F) {
|
||||
|
@ -2532,14 +2532,14 @@ class Sema {
|
||||
void AddMethodCandidate(DeclAccessPair FoundDecl,
|
||||
QualType ObjectType,
|
||||
Expr::Classification ObjectClassification,
|
||||
Expr *ThisArg, ArrayRef<Expr *> Args,
|
||||
ArrayRef<Expr *> Args,
|
||||
OverloadCandidateSet& CandidateSet,
|
||||
bool SuppressUserConversion = false);
|
||||
void AddMethodCandidate(CXXMethodDecl *Method,
|
||||
DeclAccessPair FoundDecl,
|
||||
CXXRecordDecl *ActingContext, QualType ObjectType,
|
||||
Expr::Classification ObjectClassification,
|
||||
Expr *ThisArg, ArrayRef<Expr *> Args,
|
||||
ArrayRef<Expr *> Args,
|
||||
OverloadCandidateSet& CandidateSet,
|
||||
bool SuppressUserConversions = false,
|
||||
bool PartialOverloading = false,
|
||||
@ -2550,7 +2550,6 @@ class Sema {
|
||||
TemplateArgumentListInfo *ExplicitTemplateArgs,
|
||||
QualType ObjectType,
|
||||
Expr::Classification ObjectClassification,
|
||||
Expr *ThisArg,
|
||||
ArrayRef<Expr *> Args,
|
||||
OverloadCandidateSet& CandidateSet,
|
||||
bool SuppressUserConversions = false,
|
||||
@ -2624,37 +2623,27 @@ class Sema {
|
||||
EnableIfAttr *CheckEnableIf(FunctionDecl *Function, ArrayRef<Expr *> Args,
|
||||
bool MissingImplicitThis = false);
|
||||
|
||||
/// Check the diagnose_if attributes on the given function. Returns the
|
||||
/// first succesful fatal attribute, or null if calling Function(Args) isn't
|
||||
/// an error.
|
||||
/// Emit diagnostics for the diagnose_if attributes on Function, ignoring any
|
||||
/// non-ArgDependent DiagnoseIfAttrs.
|
||||
///
|
||||
/// 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
|
||||
/// succeed. If this function returns non-null, the contents of Nonfatal are
|
||||
/// unspecified.
|
||||
DiagnoseIfAttr *
|
||||
checkArgDependentDiagnoseIf(FunctionDecl *Function, ArrayRef<Expr *> Args,
|
||||
SmallVectorImpl<DiagnoseIfAttr *> &Nonfatal,
|
||||
bool MissingImplicitThis = false,
|
||||
Expr *ThisArg = nullptr);
|
||||
/// Returns true if any errors were emitted.
|
||||
bool diagnoseArgDependentDiagnoseIfAttrs(const FunctionDecl *Function,
|
||||
const Expr *ThisArg,
|
||||
ArrayRef<const Expr *> Args,
|
||||
SourceLocation Loc);
|
||||
|
||||
/// Check the diagnose_if expressions on the given function. Returns the
|
||||
/// first succesful fatal attribute, or null if using Function isn't
|
||||
/// an error.
|
||||
/// Emit diagnostics for the diagnose_if attributes on Function, ignoring any
|
||||
/// ArgDependent DiagnoseIfAttrs.
|
||||
///
|
||||
/// 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
|
||||
/// succeed. If this function returns non-null, the contents of Nonfatal are
|
||||
/// unspecified.
|
||||
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 true if any errors were emitted.
|
||||
bool diagnoseArgIndependentDiagnoseIfAttrs(const FunctionDecl *Function,
|
||||
SourceLocation Loc);
|
||||
|
||||
/// Returns whether the given function's address can be taken or not,
|
||||
/// optionally emitting a diagnostic if the address can't be taken.
|
||||
@ -9914,8 +9903,8 @@ class Sema {
|
||||
SourceLocation Loc);
|
||||
|
||||
void checkCall(NamedDecl *FDecl, const FunctionProtoType *Proto,
|
||||
ArrayRef<const Expr *> Args, bool IsMemberFunction,
|
||||
SourceLocation Loc, SourceRange Range,
|
||||
const Expr *ThisArg, ArrayRef<const Expr *> Args,
|
||||
bool IsMemberFunction, SourceLocation Loc, SourceRange Range,
|
||||
VariadicCallType CallType);
|
||||
|
||||
bool CheckObjCString(Expr *Arg);
|
||||
|
@ -2362,7 +2362,14 @@ static unsigned getBaseIndex(const CXXRecordDecl *Derived,
|
||||
/// Extract the value of a character from a string literal.
|
||||
static APSInt extractStringLiteralCharacter(EvalInfo &Info, const Expr *Lit,
|
||||
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))
|
||||
Lit = PE->getFunctionName();
|
||||
const StringLiteral *S = cast<StringLiteral>(Lit);
|
||||
|
@ -737,7 +737,7 @@ CodeGenTypes::getCGRecordLayout(const RecordDecl *RD) {
|
||||
}
|
||||
|
||||
bool CodeGenTypes::isPointerZeroInitializable(QualType T) {
|
||||
assert (T->isAnyPointerType() && "Invalid type");
|
||||
assert((T->isAnyPointerType() || T->isBlockPointerType()) && "Invalid type");
|
||||
return isZeroInitializable(T);
|
||||
}
|
||||
|
||||
|
@ -2426,11 +2426,12 @@ static void CheckNonNullArguments(Sema &S,
|
||||
}
|
||||
|
||||
/// 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,
|
||||
ArrayRef<const Expr *> Args, bool IsMemberFunction,
|
||||
SourceLocation Loc, SourceRange Range,
|
||||
VariadicCallType CallType) {
|
||||
const Expr *ThisArg, ArrayRef<const Expr *> Args,
|
||||
bool IsMemberFunction, SourceLocation Loc,
|
||||
SourceRange Range, VariadicCallType CallType) {
|
||||
// FIXME: We should check as much as we can in the template definition.
|
||||
if (CurContext->isDependentContext())
|
||||
return;
|
||||
@ -2477,6 +2478,9 @@ void Sema::checkCall(NamedDecl *FDecl, const FunctionProtoType *Proto,
|
||||
CheckArgumentWithTypeTag(I, Args.data());
|
||||
}
|
||||
}
|
||||
|
||||
if (FD)
|
||||
diagnoseArgDependentDiagnoseIfAttrs(FD, ThisArg, Args, Loc);
|
||||
}
|
||||
|
||||
/// CheckConstructorCall - Check a constructor call for correctness and safety
|
||||
@ -2487,8 +2491,8 @@ void Sema::CheckConstructorCall(FunctionDecl *FDecl,
|
||||
SourceLocation Loc) {
|
||||
VariadicCallType CallType =
|
||||
Proto->isVariadic() ? VariadicConstructor : VariadicDoesNotApply;
|
||||
checkCall(FDecl, Proto, Args, /*IsMemberFunction=*/true, Loc, SourceRange(),
|
||||
CallType);
|
||||
checkCall(FDecl, Proto, /*ThisArg=*/nullptr, Args, /*IsMemberFunction=*/true,
|
||||
Loc, SourceRange(), CallType);
|
||||
}
|
||||
|
||||
/// CheckFunctionCall - Check a direct function call for various correctness
|
||||
@ -2503,14 +2507,20 @@ bool Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall,
|
||||
TheCall->getCallee());
|
||||
Expr** Args = TheCall->getArgs();
|
||||
unsigned NumArgs = TheCall->getNumArgs();
|
||||
|
||||
Expr *ImplicitThis = nullptr;
|
||||
if (IsMemberOperatorCall) {
|
||||
// If this is a call to a member operator, hide the first argument
|
||||
// from checkCall.
|
||||
// FIXME: Our choice of AST representation here is less than ideal.
|
||||
ImplicitThis = Args[0];
|
||||
++Args;
|
||||
--NumArgs;
|
||||
}
|
||||
checkCall(FDecl, Proto, llvm::makeArrayRef(Args, NumArgs),
|
||||
} else if (IsMemberFunction)
|
||||
ImplicitThis =
|
||||
cast<CXXMemberCallExpr>(TheCall)->getImplicitObjectArgument();
|
||||
|
||||
checkCall(FDecl, Proto, ImplicitThis, llvm::makeArrayRef(Args, NumArgs),
|
||||
IsMemberFunction, TheCall->getRParenLoc(),
|
||||
TheCall->getCallee()->getSourceRange(), CallType);
|
||||
|
||||
@ -2546,7 +2556,7 @@ bool Sema::CheckObjCMethodCall(ObjCMethodDecl *Method, SourceLocation lbrac,
|
||||
VariadicCallType CallType =
|
||||
Method->isVariadic() ? VariadicMethod : VariadicDoesNotApply;
|
||||
|
||||
checkCall(Method, nullptr, Args,
|
||||
checkCall(Method, nullptr, /*ThisArg=*/nullptr, Args,
|
||||
/*IsMemberFunction=*/false, lbrac, Method->getSourceRange(),
|
||||
CallType);
|
||||
|
||||
@ -2576,7 +2586,7 @@ bool Sema::CheckPointerCall(NamedDecl *NDecl, CallExpr *TheCall,
|
||||
CallType = VariadicFunction;
|
||||
}
|
||||
|
||||
checkCall(NDecl, Proto,
|
||||
checkCall(NDecl, Proto, /*ThisArg=*/nullptr,
|
||||
llvm::makeArrayRef(TheCall->getArgs(), TheCall->getNumArgs()),
|
||||
/*IsMemberFunction=*/false, TheCall->getRParenLoc(),
|
||||
TheCall->getCallee()->getSourceRange(), CallType);
|
||||
@ -2589,7 +2599,7 @@ bool Sema::CheckPointerCall(NamedDecl *NDecl, CallExpr *TheCall,
|
||||
bool Sema::CheckOtherCall(CallExpr *TheCall, const FunctionProtoType *Proto) {
|
||||
VariadicCallType CallType = getVariadicCallType(/*FDecl=*/nullptr, Proto,
|
||||
TheCall->getCallee());
|
||||
checkCall(/*FDecl=*/nullptr, Proto,
|
||||
checkCall(/*FDecl=*/nullptr, Proto, /*ThisArg=*/nullptr,
|
||||
llvm::makeArrayRef(TheCall->getArgs(), TheCall->getNumArgs()),
|
||||
/*IsMemberFunction=*/false, TheCall->getRParenLoc(),
|
||||
TheCall->getCallee()->getSourceRange(), CallType);
|
||||
|
@ -342,7 +342,6 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc,
|
||||
}
|
||||
|
||||
// See if this is a deleted function.
|
||||
SmallVector<DiagnoseIfAttr *, 4> DiagnoseIfWarnings;
|
||||
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
|
||||
if (FD->isDeleted()) {
|
||||
auto *Ctor = dyn_cast<CXXConstructorDecl>(FD);
|
||||
@ -365,12 +364,9 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc,
|
||||
if (getLangOpts().CUDA && !CheckCUDACall(Loc, FD))
|
||||
return true;
|
||||
|
||||
if (const DiagnoseIfAttr *A =
|
||||
checkArgIndependentDiagnoseIf(FD, DiagnoseIfWarnings)) {
|
||||
emitDiagnoseIfDiagnostic(Loc, A);
|
||||
if (diagnoseArgIndependentDiagnoseIfAttrs(FD, Loc))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// [OpenMP 4.0], 2.15 declare reduction Directive, Restrictions
|
||||
// Only the variables omp_in and omp_out are allowed in the combiner.
|
||||
@ -385,9 +381,6 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc,
|
||||
return true;
|
||||
}
|
||||
|
||||
for (const auto *W : DiagnoseIfWarnings)
|
||||
emitDiagnoseIfDiagnostic(Loc, W);
|
||||
|
||||
DiagnoseAvailabilityOfDecl(*this, D, Loc, UnknownObjCClass,
|
||||
ObjCPropertyAccess);
|
||||
|
||||
@ -5189,16 +5182,6 @@ static void checkDirectCallValidity(Sema &S, const Expr *Fn,
|
||||
<< Attr->getCond()->getSourceRange() << Attr->getMessage();
|
||||
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.
|
||||
|
@ -6712,6 +6712,11 @@ ExprResult Sema::BuildCXXMemberCallExpr(Expr *E, NamedDecl *FoundDecl,
|
||||
CXXMemberCallExpr *CE =
|
||||
new (Context) CXXMemberCallExpr(Context, ME, None, ResultType, VK,
|
||||
Exp.get()->getLocEnd());
|
||||
|
||||
if (CheckFunctionCall(Method, CE,
|
||||
Method->getType()->castAs<FunctionProtoType>()))
|
||||
return ExprError();
|
||||
|
||||
return CE;
|
||||
}
|
||||
|
||||
|
@ -2960,7 +2960,6 @@ Sema::SpecialMemberOverloadResult *Sema::LookupSpecialMember(CXXRecordDecl *RD,
|
||||
if (CXXMethodDecl *M = dyn_cast<CXXMethodDecl>(Cand->getUnderlyingDecl())) {
|
||||
if (SM == CXXCopyAssignment || SM == CXXMoveAssignment)
|
||||
AddMethodCandidate(M, Cand, RD, ThisTy, Classification,
|
||||
/*ThisArg=*/nullptr,
|
||||
llvm::makeArrayRef(&Arg, NumArgs), OCS, true);
|
||||
else if (CtorInfo)
|
||||
AddOverloadCandidate(CtorInfo.Constructor, CtorInfo.FoundDecl,
|
||||
@ -2973,7 +2972,7 @@ Sema::SpecialMemberOverloadResult *Sema::LookupSpecialMember(CXXRecordDecl *RD,
|
||||
if (SM == CXXCopyAssignment || SM == CXXMoveAssignment)
|
||||
AddMethodTemplateCandidate(
|
||||
Tmpl, Cand, RD, nullptr, ThisTy, Classification,
|
||||
/*ThisArg=*/nullptr, llvm::makeArrayRef(&Arg, NumArgs), OCS, true);
|
||||
llvm::makeArrayRef(&Arg, NumArgs), OCS, true);
|
||||
else if (CtorInfo)
|
||||
AddTemplateOverloadCandidate(
|
||||
CtorInfo.ConstructorTmpl, CtorInfo.FoundDecl, nullptr,
|
||||
|
@ -839,20 +839,12 @@ void OverloadCandidateSet::destroyCandidates() {
|
||||
|
||||
void OverloadCandidateSet::clear() {
|
||||
destroyCandidates();
|
||||
// DiagnoseIfAttrs are just pointers, so we don't need to destroy them.
|
||||
SlabAllocator.Reset();
|
||||
NumInlineBytesUsed = 0;
|
||||
Candidates.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 {
|
||||
class UnbridgedCastsSet {
|
||||
struct Entry {
|
||||
@ -5831,28 +5823,6 @@ static bool IsAcceptableNonMemberOperatorCandidate(ASTContext &Context,
|
||||
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
|
||||
/// candidate functions, using the given function call arguments. If
|
||||
/// @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
|
||||
// is irrelevant.
|
||||
AddMethodCandidate(Method, FoundDecl, Method->getParent(), QualType(),
|
||||
Expr::Classification::makeSimpleLValue(),
|
||||
/*ThisArg=*/nullptr, Args, CandidateSet,
|
||||
SuppressUserConversions, PartialOverloading,
|
||||
EarlyConversions);
|
||||
Expr::Classification::makeSimpleLValue(), Args,
|
||||
CandidateSet, SuppressUserConversions,
|
||||
PartialOverloading, EarlyConversions);
|
||||
return;
|
||||
}
|
||||
// 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;
|
||||
return;
|
||||
}
|
||||
|
||||
initDiagnoseIfComplaint(*this, CandidateSet, Candidate, Function, Args);
|
||||
}
|
||||
|
||||
ObjCMethodDecl *
|
||||
@ -6260,87 +6227,75 @@ EnableIfAttr *Sema::CheckEnableIf(FunctionDecl *Function, ArrayRef<Expr *> Args,
|
||||
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);
|
||||
template <typename CheckFn>
|
||||
static bool diagnoseDiagnoseIfAttrsWith(Sema &S, const FunctionDecl *FD,
|
||||
bool ArgDependent, SourceLocation Loc,
|
||||
CheckFn &&IsSuccessful) {
|
||||
SmallVector<const DiagnoseIfAttr *, 8> Attrs;
|
||||
for (const auto *DIA : FD->specific_attrs<DiagnoseIfAttr>()) {
|
||||
if (ArgDependent == DIA->getArgDependent())
|
||||
Attrs.push_back(DIA);
|
||||
}
|
||||
|
||||
return !Errors.empty() || !Nonfatal.empty();
|
||||
}
|
||||
// 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(); });
|
||||
|
||||
template <typename CheckFn>
|
||||
static DiagnoseIfAttr *
|
||||
checkDiagnoseIfAttrsWith(const SmallVectorImpl<DiagnoseIfAttr *> &Errors,
|
||||
SmallVectorImpl<DiagnoseIfAttr *> &Nonfatal,
|
||||
CheckFn &&IsSuccessful) {
|
||||
// Note that diagnose_if attributes are late-parsed, so they appear in the
|
||||
// correct order (unlike enable_if attributes).
|
||||
auto ErrAttr = llvm::find_if(Errors, IsSuccessful);
|
||||
if (ErrAttr != Errors.end())
|
||||
return *ErrAttr;
|
||||
auto ErrAttr = llvm::find_if(llvm::make_range(Attrs.begin(), WarningBegin),
|
||||
IsSuccessful);
|
||||
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); });
|
||||
return nullptr;
|
||||
for (const auto *DIA : llvm::make_range(WarningBegin, Attrs.end()))
|
||||
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 *
|
||||
Sema::checkArgDependentDiagnoseIf(FunctionDecl *Function, ArrayRef<Expr *> Args,
|
||||
SmallVectorImpl<DiagnoseIfAttr *> &Nonfatal,
|
||||
bool MissingImplicitThis,
|
||||
Expr *ThisArg) {
|
||||
SmallVector<DiagnoseIfAttr *, 4> Errors;
|
||||
if (!gatherDiagnoseIfAttrs(Function, /*ArgDependent=*/true, Errors, Nonfatal))
|
||||
return nullptr;
|
||||
|
||||
SFINAETrap Trap(*this);
|
||||
SmallVector<Expr *, 16> ConvertedArgs;
|
||||
Expr *ConvertedThis;
|
||||
if (!convertArgsForAvailabilityChecks(*this, Function, ThisArg, Args, Trap,
|
||||
MissingImplicitThis, ConvertedThis,
|
||||
ConvertedArgs))
|
||||
return nullptr;
|
||||
|
||||
return checkDiagnoseIfAttrsWith(Errors, Nonfatal, [&](DiagnoseIfAttr *DIA) {
|
||||
bool Sema::diagnoseArgDependentDiagnoseIfAttrs(const FunctionDecl *Function,
|
||||
const Expr *ThisArg,
|
||||
ArrayRef<const Expr *> Args,
|
||||
SourceLocation Loc) {
|
||||
return diagnoseDiagnoseIfAttrsWith(
|
||||
*this, Function, /*ArgDependent=*/true, Loc,
|
||||
[&](const 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
|
||||
// It's sane to use the same Args 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))
|
||||
Result, Context, DIA->getParent(), Args, ThisArg))
|
||||
return false;
|
||||
return Result.isInt() && Result.getInt().getBoolValue();
|
||||
});
|
||||
}
|
||||
|
||||
DiagnoseIfAttr *Sema::checkArgIndependentDiagnoseIf(
|
||||
FunctionDecl *Function, SmallVectorImpl<DiagnoseIfAttr *> &Nonfatal) {
|
||||
SmallVector<DiagnoseIfAttr *, 4> Errors;
|
||||
if (!gatherDiagnoseIfAttrs(Function, /*ArgDependent=*/false, Errors,
|
||||
Nonfatal))
|
||||
return nullptr;
|
||||
|
||||
return checkDiagnoseIfAttrsWith(Errors, Nonfatal, [&](DiagnoseIfAttr *DIA) {
|
||||
bool Sema::diagnoseArgIndependentDiagnoseIfAttrs(const FunctionDecl *Function,
|
||||
SourceLocation Loc) {
|
||||
return diagnoseDiagnoseIfAttrsWith(
|
||||
*this, Function, /*ArgDependent=*/false, Loc,
|
||||
[&](const DiagnoseIfAttr *DIA) {
|
||||
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
|
||||
/// the overload candidate set.
|
||||
void Sema::AddFunctionCandidates(const UnresolvedSetImpl &Fns,
|
||||
@ -6356,8 +6311,8 @@ void Sema::AddFunctionCandidates(const UnresolvedSetImpl &Fns,
|
||||
AddMethodCandidate(cast<CXXMethodDecl>(FD), F.getPair(),
|
||||
cast<CXXMethodDecl>(FD)->getParent(),
|
||||
Args[0]->getType(), Args[0]->Classify(Context),
|
||||
Args[0], Args.slice(1), CandidateSet,
|
||||
SuppressUserConversions, PartialOverloading);
|
||||
Args.slice(1), CandidateSet, SuppressUserConversions,
|
||||
PartialOverloading);
|
||||
else
|
||||
AddOverloadCandidate(FD, F.getPair(), Args, CandidateSet,
|
||||
SuppressUserConversions, PartialOverloading);
|
||||
@ -6369,7 +6324,7 @@ void Sema::AddFunctionCandidates(const UnresolvedSetImpl &Fns,
|
||||
FunTmpl, F.getPair(),
|
||||
cast<CXXRecordDecl>(FunTmpl->getDeclContext()),
|
||||
ExplicitTemplateArgs, Args[0]->getType(),
|
||||
Args[0]->Classify(Context), Args[0], Args.slice(1), CandidateSet,
|
||||
Args[0]->Classify(Context), Args.slice(1), CandidateSet,
|
||||
SuppressUserConversions, PartialOverloading);
|
||||
else
|
||||
AddTemplateOverloadCandidate(FunTmpl, F.getPair(),
|
||||
@ -6385,7 +6340,6 @@ void Sema::AddFunctionCandidates(const UnresolvedSetImpl &Fns,
|
||||
void Sema::AddMethodCandidate(DeclAccessPair FoundDecl,
|
||||
QualType ObjectType,
|
||||
Expr::Classification ObjectClassification,
|
||||
Expr *ThisArg,
|
||||
ArrayRef<Expr *> Args,
|
||||
OverloadCandidateSet& CandidateSet,
|
||||
bool SuppressUserConversions) {
|
||||
@ -6399,15 +6353,13 @@ void Sema::AddMethodCandidate(DeclAccessPair FoundDecl,
|
||||
assert(isa<CXXMethodDecl>(TD->getTemplatedDecl()) &&
|
||||
"Expected a member function template");
|
||||
AddMethodTemplateCandidate(TD, FoundDecl, ActingContext,
|
||||
/*ExplicitArgs*/ nullptr,
|
||||
ObjectType, ObjectClassification,
|
||||
ThisArg, Args, CandidateSet,
|
||||
/*ExplicitArgs*/ nullptr, ObjectType,
|
||||
ObjectClassification, Args, CandidateSet,
|
||||
SuppressUserConversions);
|
||||
} else {
|
||||
AddMethodCandidate(cast<CXXMethodDecl>(Decl), FoundDecl, ActingContext,
|
||||
ObjectType, ObjectClassification,
|
||||
ThisArg, Args,
|
||||
CandidateSet, SuppressUserConversions);
|
||||
ObjectType, ObjectClassification, Args, CandidateSet,
|
||||
SuppressUserConversions);
|
||||
}
|
||||
}
|
||||
|
||||
@ -6422,7 +6374,7 @@ void
|
||||
Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl,
|
||||
CXXRecordDecl *ActingContext, QualType ObjectType,
|
||||
Expr::Classification ObjectClassification,
|
||||
Expr *ThisArg, ArrayRef<Expr *> Args,
|
||||
ArrayRef<Expr *> Args,
|
||||
OverloadCandidateSet &CandidateSet,
|
||||
bool SuppressUserConversions,
|
||||
bool PartialOverloading,
|
||||
@ -6544,9 +6496,6 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl,
|
||||
Candidate.DeductionFailure.Data = FailedAttr;
|
||||
return;
|
||||
}
|
||||
|
||||
initDiagnoseIfComplaint(*this, CandidateSet, Candidate, Method, Args,
|
||||
/*MissingImplicitThis=*/!ThisArg, ThisArg);
|
||||
}
|
||||
|
||||
/// \brief Add a C++ member function template as a candidate to the candidate
|
||||
@ -6559,7 +6508,6 @@ Sema::AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl,
|
||||
TemplateArgumentListInfo *ExplicitTemplateArgs,
|
||||
QualType ObjectType,
|
||||
Expr::Classification ObjectClassification,
|
||||
Expr *ThisArg,
|
||||
ArrayRef<Expr *> Args,
|
||||
OverloadCandidateSet& CandidateSet,
|
||||
bool SuppressUserConversions,
|
||||
@ -6613,9 +6561,9 @@ Sema::AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl,
|
||||
assert(isa<CXXMethodDecl>(Specialization) &&
|
||||
"Specialization is not a member function?");
|
||||
AddMethodCandidate(cast<CXXMethodDecl>(Specialization), FoundDecl,
|
||||
ActingContext, ObjectType, ObjectClassification,
|
||||
/*ThisArg=*/ThisArg, Args, CandidateSet,
|
||||
SuppressUserConversions, PartialOverloading, Conversions);
|
||||
ActingContext, ObjectType, ObjectClassification, Args,
|
||||
CandidateSet, SuppressUserConversions, PartialOverloading,
|
||||
Conversions);
|
||||
}
|
||||
|
||||
/// \brief Add a C++ function template specialization as a candidate
|
||||
@ -6942,8 +6890,6 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion,
|
||||
Candidate.DeductionFailure.Data = FailedAttr;
|
||||
return;
|
||||
}
|
||||
|
||||
initDiagnoseIfComplaint(*this, CandidateSet, Candidate, Conversion, None, false, From);
|
||||
}
|
||||
|
||||
/// \brief Adds a conversion function template specialization
|
||||
@ -7096,8 +7042,6 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion,
|
||||
Candidate.DeductionFailure.Data = FailedAttr;
|
||||
return;
|
||||
}
|
||||
|
||||
initDiagnoseIfComplaint(*this, CandidateSet, Candidate, Conversion, None);
|
||||
}
|
||||
|
||||
/// \brief Add overload candidates for overloaded operators that are
|
||||
@ -7146,7 +7090,7 @@ void Sema::AddMemberOperatorCandidates(OverloadedOperatorKind Op,
|
||||
Oper != OperEnd;
|
||||
++Oper)
|
||||
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);
|
||||
}
|
||||
}
|
||||
@ -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)
|
||||
/// within an overload candidate set.
|
||||
///
|
||||
@ -9267,19 +9200,13 @@ OverloadCandidateSet::BestViableFunction(Sema &S, SourceLocation Loc,
|
||||
// Best is the best viable function.
|
||||
if (Best->Function &&
|
||||
(Best->Function->isDeleted() ||
|
||||
S.isFunctionConsideredUnavailable(Best->Function) ||
|
||||
isCandidateUnavailableDueToDiagnoseIf(*Best)))
|
||||
S.isFunctionConsideredUnavailable(Best->Function)))
|
||||
return OR_Deleted;
|
||||
|
||||
if (!EquivalentCands.empty())
|
||||
S.diagnoseEquivalentInternalLinkageDeclarations(Loc, Best->Function,
|
||||
EquivalentCands);
|
||||
|
||||
for (const auto *W : Best->getDiagnoseIfInfo()) {
|
||||
assert(W->isWarning() && "Errors should've been caught earlier!");
|
||||
S.emitDiagnoseIfDiagnostic(Loc, W);
|
||||
}
|
||||
|
||||
return OR_Success;
|
||||
}
|
||||
|
||||
@ -10162,14 +10089,6 @@ static void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand,
|
||||
MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl);
|
||||
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.
|
||||
S.NoteOverloadCandidate(Cand->FoundDecl, Fn);
|
||||
@ -12113,6 +12032,10 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, UnaryOperatorKind Opc,
|
||||
if (CheckCallReturnType(FnDecl->getReturnType(), OpLoc, TheCall, FnDecl))
|
||||
return ExprError();
|
||||
|
||||
if (CheckFunctionCall(FnDecl, TheCall,
|
||||
FnDecl->getType()->castAs<FunctionProtoType>()))
|
||||
return ExprError();
|
||||
|
||||
return MaybeBindToTemporary(TheCall);
|
||||
} else {
|
||||
// We matched a built-in operator. Convert the arguments, then
|
||||
@ -12343,16 +12266,20 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
|
||||
return ExprError();
|
||||
|
||||
ArrayRef<const Expr *> ArgsArray(Args, 2);
|
||||
const Expr *ImplicitThis = nullptr;
|
||||
// Cut off the implicit 'this'.
|
||||
if (isa<CXXMethodDecl>(FnDecl))
|
||||
if (isa<CXXMethodDecl>(FnDecl)) {
|
||||
ImplicitThis = ArgsArray[0];
|
||||
ArgsArray = ArgsArray.slice(1);
|
||||
}
|
||||
|
||||
// Check for a self move.
|
||||
if (Op == OO_Equal)
|
||||
DiagnoseSelfMove(Args[0], Args[1], OpLoc);
|
||||
|
||||
checkCall(FnDecl, nullptr, ArgsArray, isa<CXXMethodDecl>(FnDecl), OpLoc,
|
||||
TheCall->getSourceRange(), VariadicDoesNotApply);
|
||||
checkCall(FnDecl, nullptr, ImplicitThis, ArgsArray,
|
||||
isa<CXXMethodDecl>(FnDecl), OpLoc, TheCall->getSourceRange(),
|
||||
VariadicDoesNotApply);
|
||||
|
||||
return MaybeBindToTemporary(TheCall);
|
||||
} else {
|
||||
@ -12561,6 +12488,10 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
|
||||
if (CheckCallReturnType(FnDecl->getReturnType(), LLoc, TheCall, FnDecl))
|
||||
return ExprError();
|
||||
|
||||
if (CheckFunctionCall(Method, TheCall,
|
||||
Method->getType()->castAs<FunctionProtoType>()))
|
||||
return ExprError();
|
||||
|
||||
return MaybeBindToTemporary(TheCall);
|
||||
} else {
|
||||
// We matched a built-in operator. Convert the arguments, then
|
||||
@ -12727,16 +12658,6 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
|
||||
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(),
|
||||
E = UnresExpr->decls_end(); I != E; ++I) {
|
||||
|
||||
@ -12757,14 +12678,12 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
|
||||
continue;
|
||||
|
||||
AddMethodCandidate(Method, I.getPair(), ActingDC, ObjectType,
|
||||
ObjectClassification,
|
||||
/*ThisArg=*/GetUnresolvedBase(), Args, CandidateSet,
|
||||
ObjectClassification, Args, CandidateSet,
|
||||
/*SuppressUserConversions=*/false);
|
||||
} else {
|
||||
AddMethodTemplateCandidate(
|
||||
cast<FunctionTemplateDecl>(Func), I.getPair(), ActingDC,
|
||||
TemplateArgs, ObjectType, ObjectClassification,
|
||||
/*ThisArg=*/GetUnresolvedBase(), Args, CandidateSet,
|
||||
TemplateArgs, ObjectType, ObjectClassification, Args, CandidateSet,
|
||||
/*SuppressUsedConversions=*/false);
|
||||
}
|
||||
}
|
||||
@ -12882,16 +12801,6 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
|
||||
<< Attr->getCond()->getSourceRange() << Attr->getMessage();
|
||||
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) ||
|
||||
@ -12970,9 +12879,8 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj,
|
||||
for (LookupResult::iterator Oper = R.begin(), OperEnd = R.end();
|
||||
Oper != OperEnd; ++Oper) {
|
||||
AddMethodCandidate(Oper.getPair(), Object.get()->getType(),
|
||||
Object.get()->Classify(Context),
|
||||
Object.get(), Args, CandidateSet,
|
||||
/*SuppressUserConversions=*/ false);
|
||||
Object.get()->Classify(Context), Args, CandidateSet,
|
||||
/*SuppressUserConversions=*/false);
|
||||
}
|
||||
|
||||
// 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();
|
||||
Oper != OperEnd; ++Oper) {
|
||||
AddMethodCandidate(Oper.getPair(), Base->getType(), Base->Classify(Context),
|
||||
Base, None, CandidateSet,
|
||||
/*SuppressUserConversions=*/false);
|
||||
None, CandidateSet, /*SuppressUserConversions=*/false);
|
||||
}
|
||||
|
||||
bool HadMultipleCandidates = (CandidateSet.size() > 1);
|
||||
@ -13324,6 +13231,10 @@ Sema::BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc,
|
||||
if (CheckCallReturnType(Method->getReturnType(), OpLoc, TheCall, Method))
|
||||
return ExprError();
|
||||
|
||||
if (CheckFunctionCall(Method, TheCall,
|
||||
Method->getType()->castAs<FunctionProtoType>()))
|
||||
return ExprError();
|
||||
|
||||
return MaybeBindToTemporary(TheCall);
|
||||
}
|
||||
|
||||
|
@ -4996,8 +4996,12 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
|
||||
NamedDecl *Result = nullptr;
|
||||
// FIXME: If the name is a dependent name, this lookup won't necessarily
|
||||
// find it. Does that ever matter?
|
||||
if (D->getDeclName()) {
|
||||
DeclContext::lookup_result Found = ParentDC->lookup(D->getDeclName());
|
||||
if (auto Name = 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());
|
||||
} else {
|
||||
// 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
|
||||
// nested-name-qualifier (and therefore could do the lookup).
|
||||
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,
|
||||
E->isArrow(),
|
||||
QualifierLoc,
|
||||
TemplateKWLoc,
|
||||
E->getMemberNameInfo(),
|
||||
MemberNameInfo,
|
||||
Member,
|
||||
FoundDecl,
|
||||
(E->hasExplicitTemplateArgs()
|
||||
|
@ -180,10 +180,6 @@ template <class ELFT> class ObjectFile : public ELFFileBase<ELFT> {
|
||||
// R_MIPS_GPREL16 / R_MIPS_GPREL32 relocations.
|
||||
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,
|
||||
// or empty string if there is no such symbol in object file
|
||||
// symbol table.
|
||||
|
@ -246,7 +246,8 @@ void InputSection<ELFT>::copyRelocations(uint8_t *Buf, ArrayRef<RelTy> Rels) {
|
||||
if (Config->Rela)
|
||||
P->r_addend = getAddend<ELFT>(Rel);
|
||||
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->Entsize = this->Entsize;
|
||||
|
||||
if (Config->Relocatable) {
|
||||
size_t I = NumLocals;
|
||||
for (const SymbolTableEntry &S : Symbols)
|
||||
S.Symbol->DynsymIndex = ++I;
|
||||
if (Config->Relocatable)
|
||||
return;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
// NB: It also sorts Symbols to meet the GNU hash table requirements.
|
||||
In<ELFT>::GnuHashTab->addSymbols(Symbols);
|
||||
@ -1094,10 +1093,25 @@ template <class ELFT> void SymbolTableSection<ELFT>::finalize() {
|
||||
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)});
|
||||
}
|
||||
|
||||
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) {
|
||||
Buf += sizeof(Elf_Sym);
|
||||
|
||||
@ -1113,10 +1127,9 @@ template <class ELFT>
|
||||
void SymbolTableSection<ELFT>::writeLocalSymbols(uint8_t *&Buf) {
|
||||
// Iterate over all input object files to copy their local symbols
|
||||
// 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;
|
||||
|
||||
for (auto I = Symbols.begin(); I != Symbols.begin() + NumLocals; ++I) {
|
||||
const DefinedRegular<ELFT> &Body = *cast<DefinedRegular<ELFT>>(I->Symbol);
|
||||
InputSectionBase<ELFT> *Section = Body.Section;
|
||||
auto *ESym = reinterpret_cast<Elf_Sym *>(Buf);
|
||||
|
||||
@ -1128,12 +1141,11 @@ void SymbolTableSection<ELFT>::writeLocalSymbols(uint8_t *&Buf) {
|
||||
ESym->st_shndx = OutSec->SectionIndex;
|
||||
ESym->st_value = OutSec->Addr + Section->getOffset(Body);
|
||||
}
|
||||
ESym->st_name = P.second;
|
||||
ESym->st_name = I->StrTabOffset;
|
||||
ESym->st_size = Body.template getSize<ELFT>();
|
||||
ESym->setBindingAndType(STB_LOCAL, Body.Type);
|
||||
Buf += sizeof(*ESym);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
@ -1141,7 +1153,9 @@ void SymbolTableSection<ELFT>::writeGlobalSymbols(uint8_t *Buf) {
|
||||
// Write the internal symbol table contents to the output symbol table
|
||||
// pointed by 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;
|
||||
size_t StrOff = S.StrTabOffset;
|
||||
|
||||
|
@ -366,23 +366,26 @@ class SymbolTableSection final : public SyntheticSection<ELFT> {
|
||||
void finalize() override;
|
||||
void writeTo(uint8_t *Buf) override;
|
||||
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; }
|
||||
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; }
|
||||
|
||||
static const OutputSectionBase *getOutputSection(SymbolBody *Sym);
|
||||
|
||||
unsigned NumLocals = 0;
|
||||
StringTableSection<ELFT> &StrTabSec;
|
||||
|
||||
private:
|
||||
void writeLocalSymbols(uint8_t *&Buf);
|
||||
void writeGlobalSymbols(uint8_t *Buf);
|
||||
|
||||
// A vector of symbols and their string table offsets.
|
||||
std::vector<SymbolTableEntry> Symbols;
|
||||
|
||||
StringTableSection<ELFT> &StrTabSec;
|
||||
|
||||
unsigned NumLocals = 0;
|
||||
};
|
||||
|
||||
// Outputs GNU Hash section. For detailed explanation see:
|
||||
|
@ -455,11 +455,7 @@ template <class ELFT> void Writer<ELFT>::copyLocalSymbols() {
|
||||
InputSectionBase<ELFT> *Sec = DR->Section;
|
||||
if (!shouldKeepInSymtab<ELFT>(Sec, B->getName(), *B))
|
||||
continue;
|
||||
++In<ELFT>::SymTab->NumLocals;
|
||||
if (Config->Relocatable)
|
||||
B->DynsymIndex = In<ELFT>::SymTab->NumLocals;
|
||||
F->KeptLocalSyms.push_back(std::make_pair(
|
||||
DR, In<ELFT>::SymTab->StrTabSec.addString(B->getName())));
|
||||
In<ELFT>::SymTab->addLocal(B);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1024,10 +1020,10 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
|
||||
if (!includeInSymtab<ELFT>(*Body))
|
||||
continue;
|
||||
if (In<ELFT>::SymTab)
|
||||
In<ELFT>::SymTab->addSymbol(Body);
|
||||
In<ELFT>::SymTab->addGlobal(Body);
|
||||
|
||||
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 (SS->file()->isNeeded())
|
||||
In<ELFT>::VerNeed->addSymbol(SS);
|
||||
|
@ -8,4 +8,4 @@
|
||||
|
||||
#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_MAJOR 4
|
||||
#define LLD_VERSION_MINOR 0
|
||||
#define LLD_REVISION_STRING "293443"
|
||||
#define LLD_REVISION_STRING "293807"
|
||||
#define LLD_REPOSITORY_STRING "FreeBSD"
|
||||
|
Loading…
Reference in New Issue
Block a user