Merge llvm, clang, compiler-rt, libc++, lld, and lldb release_80 branch
r353167, resolve conflicts, and bump version numbers.
This commit is contained in:
commit
c8630eab15
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/projects/clang800-import/; revision=343806
@ -481,6 +481,7 @@ class Value {
|
||||
mutable llvm::AlignedCharArrayUnion<bool, double, int64_t, llvm::StringRef,
|
||||
std::string, json::Array, json::Object>
|
||||
Union;
|
||||
friend bool operator==(const Value &, const Value &);
|
||||
};
|
||||
|
||||
bool operator==(const Value &, const Value &);
|
||||
|
@ -44,6 +44,11 @@ class FunctionImportGlobalProcessing {
|
||||
/// to promote any non-renamable values.
|
||||
SmallPtrSet<GlobalValue *, 8> Used;
|
||||
|
||||
/// Keep track of any COMDATs that require renaming (because COMDAT
|
||||
/// leader was promoted and renamed). Maps from original COMDAT to one
|
||||
/// with new name.
|
||||
DenseMap<const Comdat *, Comdat *> RenamedComdats;
|
||||
|
||||
/// Check if we should promote the given local value to global scope.
|
||||
bool shouldPromoteLocalToGlobal(const GlobalValue *SGV);
|
||||
|
||||
|
@ -1836,7 +1836,10 @@ TypeIndex CodeViewDebug::lowerTypeMemberFunction(const DISubroutineType *Ty,
|
||||
|
||||
unsigned Index = 0;
|
||||
SmallVector<TypeIndex, 8> ArgTypeIndices;
|
||||
TypeIndex ReturnTypeIndex = getTypeIndex(ReturnAndArgs[Index++]);
|
||||
TypeIndex ReturnTypeIndex = TypeIndex::Void();
|
||||
if (ReturnAndArgs.size() > Index) {
|
||||
ReturnTypeIndex = getTypeIndex(ReturnAndArgs[Index++]);
|
||||
}
|
||||
|
||||
// If the first argument is a pointer type and this isn't a static method,
|
||||
// treat it as the special 'this' parameter, which is encoded separately from
|
||||
|
@ -1956,8 +1956,10 @@ void DebugLocEntry::finalize(const AsmPrinter &AP,
|
||||
void DwarfDebug::emitDebugLocEntryLocation(const DebugLocStream::Entry &Entry) {
|
||||
// Emit the size.
|
||||
Asm->OutStreamer->AddComment("Loc expr size");
|
||||
Asm->emitInt16(DebugLocs.getBytes(Entry).size());
|
||||
|
||||
if (getDwarfVersion() >= 5)
|
||||
Asm->EmitULEB128(DebugLocs.getBytes(Entry).size());
|
||||
else
|
||||
Asm->emitInt16(DebugLocs.getBytes(Entry).size());
|
||||
// Emit the entry.
|
||||
APByteStreamer Streamer(*Asm);
|
||||
emitDebugLocEntry(Streamer, Entry);
|
||||
|
@ -225,12 +225,13 @@ void MachineInstr::addOperand(MachineFunction &MF, const MachineOperand &Op) {
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
bool isMetaDataOp = Op.getType() == MachineOperand::MO_Metadata;
|
||||
bool isDebugOp = Op.getType() == MachineOperand::MO_Metadata ||
|
||||
Op.getType() == MachineOperand::MO_MCSymbol;
|
||||
// OpNo now points as the desired insertion point. Unless this is a variadic
|
||||
// instruction, only implicit regs are allowed beyond MCID->getNumOperands().
|
||||
// RegMask operands go between the explicit and implicit operands.
|
||||
assert((isImpReg || Op.isRegMask() || MCID->isVariadic() ||
|
||||
OpNo < MCID->getNumOperands() || isMetaDataOp) &&
|
||||
OpNo < MCID->getNumOperands() || isDebugOp) &&
|
||||
"Trying to add an operand to a machine instr that is already done!");
|
||||
#endif
|
||||
|
||||
|
@ -16214,23 +16214,29 @@ static SDValue reduceBuildVecToShuffleWithZero(SDNode *BV, SelectionDAG &DAG) {
|
||||
// The build vector contains some number of undef elements and exactly
|
||||
// one other element. That other element must be a zero-extended scalar
|
||||
// extracted from a vector at a constant index to turn this into a shuffle.
|
||||
// Also, require that the build vector does not implicitly truncate/extend
|
||||
// its elements.
|
||||
// TODO: This could be enhanced to allow ANY_EXTEND as well as ZERO_EXTEND.
|
||||
EVT VT = BV->getValueType(0);
|
||||
SDValue Zext = BV->getOperand(ZextElt);
|
||||
if (Zext.getOpcode() != ISD::ZERO_EXTEND || !Zext.hasOneUse() ||
|
||||
Zext.getOperand(0).getOpcode() != ISD::EXTRACT_VECTOR_ELT ||
|
||||
!isa<ConstantSDNode>(Zext.getOperand(0).getOperand(1)))
|
||||
!isa<ConstantSDNode>(Zext.getOperand(0).getOperand(1)) ||
|
||||
Zext.getValueSizeInBits() != VT.getScalarSizeInBits())
|
||||
return SDValue();
|
||||
|
||||
// The zero-extend must be a multiple of the source size.
|
||||
// The zero-extend must be a multiple of the source size, and we must be
|
||||
// building a vector of the same size as the source of the extract element.
|
||||
SDValue Extract = Zext.getOperand(0);
|
||||
unsigned DestSize = Zext.getValueSizeInBits();
|
||||
unsigned SrcSize = Extract.getValueSizeInBits();
|
||||
if (DestSize % SrcSize != 0)
|
||||
if (DestSize % SrcSize != 0 ||
|
||||
Extract.getOperand(0).getValueSizeInBits() != VT.getSizeInBits())
|
||||
return SDValue();
|
||||
|
||||
// Create a shuffle mask that will combine the extracted element with zeros
|
||||
// and undefs.
|
||||
int ZextRatio = DestSize / SrcSize;
|
||||
int ZextRatio = DestSize / SrcSize;
|
||||
int NumMaskElts = NumBVOps * ZextRatio;
|
||||
SmallVector<int, 32> ShufMask(NumMaskElts, -1);
|
||||
for (int i = 0; i != NumMaskElts; ++i) {
|
||||
@ -16260,7 +16266,7 @@ static SDValue reduceBuildVecToShuffleWithZero(SDNode *BV, SelectionDAG &DAG) {
|
||||
SDValue ZeroVec = DAG.getConstant(0, DL, VecVT);
|
||||
SDValue Shuf = DAG.getVectorShuffle(VecVT, DL, Extract.getOperand(0), ZeroVec,
|
||||
ShufMask);
|
||||
return DAG.getBitcast(BV->getValueType(0), Shuf);
|
||||
return DAG.getBitcast(VT, Shuf);
|
||||
}
|
||||
|
||||
// Check to see if this is a BUILD_VECTOR of a bunch of EXTRACT_VECTOR_ELT
|
||||
|
@ -184,7 +184,8 @@ DWARFDebugLoclists::parseOneLocationList(DataExtractor Data, unsigned *Offset,
|
||||
}
|
||||
|
||||
if (Kind != dwarf::DW_LLE_base_address) {
|
||||
unsigned Bytes = Data.getU16(Offset);
|
||||
unsigned Bytes =
|
||||
Version >= 5 ? Data.getULEB128(Offset) : Data.getU16(Offset);
|
||||
// A single location description describing the location of the object...
|
||||
StringRef str = Data.getData().substr(*Offset, Bytes);
|
||||
*Offset += Bytes;
|
||||
|
@ -469,6 +469,11 @@ static bool UpgradeX86IntrinsicFunction(Function *F, StringRef Name,
|
||||
}
|
||||
}
|
||||
|
||||
if (Name == "seh.recoverfp") {
|
||||
NewFn = Intrinsic::getDeclaration(F->getParent(), Intrinsic::eh_recoverfp);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -544,10 +549,6 @@ static bool UpgradeIntrinsicFunction1(Function *F, Function *&NewFn) {
|
||||
NewFn = Intrinsic::getDeclaration(F->getParent(), Intrinsic::thread_pointer);
|
||||
return true;
|
||||
}
|
||||
if (Name == "x86.seh.recoverfp") {
|
||||
NewFn = Intrinsic::getDeclaration(F->getParent(), Intrinsic::eh_recoverfp);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -182,6 +182,12 @@ bool operator==(const Value &L, const Value &R) {
|
||||
case Value::Boolean:
|
||||
return *L.getAsBoolean() == *R.getAsBoolean();
|
||||
case Value::Number:
|
||||
// Workaround for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=323
|
||||
// The same integer must convert to the same double, per the standard.
|
||||
// However we see 64-vs-80-bit precision comparisons with gcc-7 -O3 -m32.
|
||||
// So we avoid floating point promotion for exact comparisons.
|
||||
if (L.Type == Value::T_Integer || R.Type == Value::T_Integer)
|
||||
return L.getAsInteger() == R.getAsInteger();
|
||||
return *L.getAsNumber() == *R.getAsNumber();
|
||||
case Value::String:
|
||||
return *L.getAsString() == *R.getAsString();
|
||||
|
@ -103,6 +103,7 @@
|
||||
#include "llvm/CodeGen/MachineInstrBuilder.h"
|
||||
#include "llvm/CodeGen/MachineOperand.h"
|
||||
#include "llvm/CodeGen/MachineRegisterInfo.h"
|
||||
#include "llvm/CodeGen/RegisterScavenging.h"
|
||||
#include "llvm/IR/DebugLoc.h"
|
||||
#include "llvm/Pass.h"
|
||||
#include "llvm/Support/CodeGen.h"
|
||||
@ -146,25 +147,31 @@ class AArch64SpeculationHardening : public MachineFunctionPass {
|
||||
BitVector RegsAlreadyMasked;
|
||||
|
||||
bool functionUsesHardeningRegister(MachineFunction &MF) const;
|
||||
bool instrumentControlFlow(MachineBasicBlock &MBB);
|
||||
bool instrumentControlFlow(MachineBasicBlock &MBB,
|
||||
bool &UsesFullSpeculationBarrier);
|
||||
bool endsWithCondControlFlow(MachineBasicBlock &MBB, MachineBasicBlock *&TBB,
|
||||
MachineBasicBlock *&FBB,
|
||||
AArch64CC::CondCode &CondCode) const;
|
||||
void insertTrackingCode(MachineBasicBlock &SplitEdgeBB,
|
||||
AArch64CC::CondCode &CondCode, DebugLoc DL) const;
|
||||
void insertSPToRegTaintPropagation(MachineBasicBlock *MBB,
|
||||
void insertSPToRegTaintPropagation(MachineBasicBlock &MBB,
|
||||
MachineBasicBlock::iterator MBBI) const;
|
||||
void insertRegToSPTaintPropagation(MachineBasicBlock *MBB,
|
||||
void insertRegToSPTaintPropagation(MachineBasicBlock &MBB,
|
||||
MachineBasicBlock::iterator MBBI,
|
||||
unsigned TmpReg) const;
|
||||
void insertFullSpeculationBarrier(MachineBasicBlock &MBB,
|
||||
MachineBasicBlock::iterator MBBI,
|
||||
DebugLoc DL) const;
|
||||
|
||||
bool slhLoads(MachineBasicBlock &MBB);
|
||||
bool makeGPRSpeculationSafe(MachineBasicBlock &MBB,
|
||||
MachineBasicBlock::iterator MBBI,
|
||||
MachineInstr &MI, unsigned Reg);
|
||||
bool lowerSpeculationSafeValuePseudos(MachineBasicBlock &MBB);
|
||||
bool lowerSpeculationSafeValuePseudos(MachineBasicBlock &MBB,
|
||||
bool UsesFullSpeculationBarrier);
|
||||
bool expandSpeculationSafeValue(MachineBasicBlock &MBB,
|
||||
MachineBasicBlock::iterator MBBI);
|
||||
MachineBasicBlock::iterator MBBI,
|
||||
bool UsesFullSpeculationBarrier);
|
||||
bool insertCSDB(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
|
||||
DebugLoc DL);
|
||||
};
|
||||
@ -207,15 +214,19 @@ bool AArch64SpeculationHardening::endsWithCondControlFlow(
|
||||
return true;
|
||||
}
|
||||
|
||||
void AArch64SpeculationHardening::insertFullSpeculationBarrier(
|
||||
MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
|
||||
DebugLoc DL) const {
|
||||
// A full control flow speculation barrier consists of (DSB SYS + ISB)
|
||||
BuildMI(MBB, MBBI, DL, TII->get(AArch64::DSB)).addImm(0xf);
|
||||
BuildMI(MBB, MBBI, DL, TII->get(AArch64::ISB)).addImm(0xf);
|
||||
}
|
||||
|
||||
void AArch64SpeculationHardening::insertTrackingCode(
|
||||
MachineBasicBlock &SplitEdgeBB, AArch64CC::CondCode &CondCode,
|
||||
DebugLoc DL) const {
|
||||
if (UseControlFlowSpeculationBarrier) {
|
||||
// insert full control flow speculation barrier (DSB SYS + ISB)
|
||||
BuildMI(SplitEdgeBB, SplitEdgeBB.begin(), DL, TII->get(AArch64::ISB))
|
||||
.addImm(0xf);
|
||||
BuildMI(SplitEdgeBB, SplitEdgeBB.begin(), DL, TII->get(AArch64::DSB))
|
||||
.addImm(0xf);
|
||||
insertFullSpeculationBarrier(SplitEdgeBB, SplitEdgeBB.begin(), DL);
|
||||
} else {
|
||||
BuildMI(SplitEdgeBB, SplitEdgeBB.begin(), DL, TII->get(AArch64::CSELXr))
|
||||
.addDef(MisspeculatingTaintReg)
|
||||
@ -227,7 +238,7 @@ void AArch64SpeculationHardening::insertTrackingCode(
|
||||
}
|
||||
|
||||
bool AArch64SpeculationHardening::instrumentControlFlow(
|
||||
MachineBasicBlock &MBB) {
|
||||
MachineBasicBlock &MBB, bool &UsesFullSpeculationBarrier) {
|
||||
LLVM_DEBUG(dbgs() << "Instrument control flow tracking on MBB: " << MBB);
|
||||
|
||||
bool Modified = false;
|
||||
@ -263,55 +274,105 @@ bool AArch64SpeculationHardening::instrumentControlFlow(
|
||||
}
|
||||
|
||||
// Perform correct code generation around function calls and before returns.
|
||||
{
|
||||
SmallVector<MachineInstr *, 4> ReturnInstructions;
|
||||
SmallVector<MachineInstr *, 4> CallInstructions;
|
||||
// The below variables record the return/terminator instructions and the call
|
||||
// instructions respectively; including which register is available as a
|
||||
// temporary register just before the recorded instructions.
|
||||
SmallVector<std::pair<MachineInstr *, unsigned>, 4> ReturnInstructions;
|
||||
SmallVector<std::pair<MachineInstr *, unsigned>, 4> CallInstructions;
|
||||
// if a temporary register is not available for at least one of the
|
||||
// instructions for which we need to transfer taint to the stack pointer, we
|
||||
// need to insert a full speculation barrier.
|
||||
// TmpRegisterNotAvailableEverywhere tracks that condition.
|
||||
bool TmpRegisterNotAvailableEverywhere = false;
|
||||
|
||||
for (MachineInstr &MI : MBB) {
|
||||
if (MI.isReturn())
|
||||
ReturnInstructions.push_back(&MI);
|
||||
else if (MI.isCall())
|
||||
CallInstructions.push_back(&MI);
|
||||
}
|
||||
RegScavenger RS;
|
||||
RS.enterBasicBlock(MBB);
|
||||
|
||||
Modified |=
|
||||
(ReturnInstructions.size() > 0) || (CallInstructions.size() > 0);
|
||||
for (MachineBasicBlock::iterator I = MBB.begin(); I != MBB.end(); I++) {
|
||||
MachineInstr &MI = *I;
|
||||
if (!MI.isReturn() && !MI.isCall())
|
||||
continue;
|
||||
|
||||
for (MachineInstr *Return : ReturnInstructions)
|
||||
insertRegToSPTaintPropagation(Return->getParent(), Return, AArch64::X17);
|
||||
for (MachineInstr *Call : CallInstructions) {
|
||||
// Just after the call:
|
||||
MachineBasicBlock::iterator i = Call;
|
||||
i++;
|
||||
insertSPToRegTaintPropagation(Call->getParent(), i);
|
||||
// Just before the call:
|
||||
insertRegToSPTaintPropagation(Call->getParent(), Call, AArch64::X17);
|
||||
}
|
||||
// The RegScavenger represents registers available *after* the MI
|
||||
// instruction pointed to by RS.getCurrentPosition().
|
||||
// We need to have a register that is available *before* the MI is executed.
|
||||
if (I != MBB.begin())
|
||||
RS.forward(std::prev(I));
|
||||
// FIXME: The below just finds *a* unused register. Maybe code could be
|
||||
// optimized more if this looks for the register that isn't used for the
|
||||
// longest time around this place, to enable more scheduling freedom. Not
|
||||
// sure if that would actually result in a big performance difference
|
||||
// though. Maybe RegisterScavenger::findSurvivorBackwards has some logic
|
||||
// already to do this - but it's unclear if that could easily be used here.
|
||||
unsigned TmpReg = RS.FindUnusedReg(&AArch64::GPR64commonRegClass);
|
||||
LLVM_DEBUG(dbgs() << "RS finds "
|
||||
<< ((TmpReg == 0) ? "no register " : "register ");
|
||||
if (TmpReg != 0) dbgs() << printReg(TmpReg, TRI) << " ";
|
||||
dbgs() << "to be available at MI " << MI);
|
||||
if (TmpReg == 0)
|
||||
TmpRegisterNotAvailableEverywhere = true;
|
||||
if (MI.isReturn())
|
||||
ReturnInstructions.push_back({&MI, TmpReg});
|
||||
else if (MI.isCall())
|
||||
CallInstructions.push_back({&MI, TmpReg});
|
||||
}
|
||||
|
||||
if (TmpRegisterNotAvailableEverywhere) {
|
||||
// When a temporary register is not available everywhere in this basic
|
||||
// basic block where a propagate-taint-to-sp operation is needed, just
|
||||
// emit a full speculation barrier at the start of this basic block, which
|
||||
// renders the taint/speculation tracking in this basic block unnecessary.
|
||||
insertFullSpeculationBarrier(MBB, MBB.begin(),
|
||||
(MBB.begin())->getDebugLoc());
|
||||
UsesFullSpeculationBarrier = true;
|
||||
Modified = true;
|
||||
} else {
|
||||
for (auto MI_Reg : ReturnInstructions) {
|
||||
assert(MI_Reg.second != 0);
|
||||
LLVM_DEBUG(
|
||||
dbgs()
|
||||
<< " About to insert Reg to SP taint propagation with temp register "
|
||||
<< printReg(MI_Reg.second, TRI)
|
||||
<< " on instruction: " << *MI_Reg.first);
|
||||
insertRegToSPTaintPropagation(MBB, MI_Reg.first, MI_Reg.second);
|
||||
Modified = true;
|
||||
}
|
||||
|
||||
for (auto MI_Reg : CallInstructions) {
|
||||
assert(MI_Reg.second != 0);
|
||||
LLVM_DEBUG(dbgs() << " About to insert Reg to SP and back taint "
|
||||
"propagation with temp register "
|
||||
<< printReg(MI_Reg.second, TRI)
|
||||
<< " around instruction: " << *MI_Reg.first);
|
||||
// Just after the call:
|
||||
insertSPToRegTaintPropagation(
|
||||
MBB, std::next((MachineBasicBlock::iterator)MI_Reg.first));
|
||||
// Just before the call:
|
||||
insertRegToSPTaintPropagation(MBB, MI_Reg.first, MI_Reg.second);
|
||||
Modified = true;
|
||||
}
|
||||
}
|
||||
return Modified;
|
||||
}
|
||||
|
||||
void AArch64SpeculationHardening::insertSPToRegTaintPropagation(
|
||||
MachineBasicBlock *MBB, MachineBasicBlock::iterator MBBI) const {
|
||||
MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI) const {
|
||||
// If full control flow speculation barriers are used, emit a control flow
|
||||
// barrier to block potential miss-speculation in flight coming in to this
|
||||
// function.
|
||||
if (UseControlFlowSpeculationBarrier) {
|
||||
// insert full control flow speculation barrier (DSB SYS + ISB)
|
||||
BuildMI(*MBB, MBBI, DebugLoc(), TII->get(AArch64::DSB)).addImm(0xf);
|
||||
BuildMI(*MBB, MBBI, DebugLoc(), TII->get(AArch64::ISB)).addImm(0xf);
|
||||
insertFullSpeculationBarrier(MBB, MBBI, DebugLoc());
|
||||
return;
|
||||
}
|
||||
|
||||
// CMP SP, #0 === SUBS xzr, SP, #0
|
||||
BuildMI(*MBB, MBBI, DebugLoc(), TII->get(AArch64::SUBSXri))
|
||||
BuildMI(MBB, MBBI, DebugLoc(), TII->get(AArch64::SUBSXri))
|
||||
.addDef(AArch64::XZR)
|
||||
.addUse(AArch64::SP)
|
||||
.addImm(0)
|
||||
.addImm(0); // no shift
|
||||
// CSETM x16, NE === CSINV x16, xzr, xzr, EQ
|
||||
BuildMI(*MBB, MBBI, DebugLoc(), TII->get(AArch64::CSINVXr))
|
||||
BuildMI(MBB, MBBI, DebugLoc(), TII->get(AArch64::CSINVXr))
|
||||
.addDef(MisspeculatingTaintReg)
|
||||
.addUse(AArch64::XZR)
|
||||
.addUse(AArch64::XZR)
|
||||
@ -319,7 +380,7 @@ void AArch64SpeculationHardening::insertSPToRegTaintPropagation(
|
||||
}
|
||||
|
||||
void AArch64SpeculationHardening::insertRegToSPTaintPropagation(
|
||||
MachineBasicBlock *MBB, MachineBasicBlock::iterator MBBI,
|
||||
MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
|
||||
unsigned TmpReg) const {
|
||||
// If full control flow speculation barriers are used, there will not be
|
||||
// miss-speculation when returning from this function, and therefore, also
|
||||
@ -328,19 +389,19 @@ void AArch64SpeculationHardening::insertRegToSPTaintPropagation(
|
||||
return;
|
||||
|
||||
// mov Xtmp, SP === ADD Xtmp, SP, #0
|
||||
BuildMI(*MBB, MBBI, DebugLoc(), TII->get(AArch64::ADDXri))
|
||||
BuildMI(MBB, MBBI, DebugLoc(), TII->get(AArch64::ADDXri))
|
||||
.addDef(TmpReg)
|
||||
.addUse(AArch64::SP)
|
||||
.addImm(0)
|
||||
.addImm(0); // no shift
|
||||
// and Xtmp, Xtmp, TaintReg === AND Xtmp, Xtmp, TaintReg, #0
|
||||
BuildMI(*MBB, MBBI, DebugLoc(), TII->get(AArch64::ANDXrs))
|
||||
BuildMI(MBB, MBBI, DebugLoc(), TII->get(AArch64::ANDXrs))
|
||||
.addDef(TmpReg, RegState::Renamable)
|
||||
.addUse(TmpReg, RegState::Kill | RegState::Renamable)
|
||||
.addUse(MisspeculatingTaintReg, RegState::Kill)
|
||||
.addImm(0);
|
||||
// mov SP, Xtmp === ADD SP, Xtmp, #0
|
||||
BuildMI(*MBB, MBBI, DebugLoc(), TII->get(AArch64::ADDXri))
|
||||
BuildMI(MBB, MBBI, DebugLoc(), TII->get(AArch64::ADDXri))
|
||||
.addDef(AArch64::SP)
|
||||
.addUse(TmpReg, RegState::Kill)
|
||||
.addImm(0)
|
||||
@ -484,7 +545,8 @@ bool AArch64SpeculationHardening::slhLoads(MachineBasicBlock &MBB) {
|
||||
/// \brief If MBBI references a pseudo instruction that should be expanded
|
||||
/// here, do the expansion and return true. Otherwise return false.
|
||||
bool AArch64SpeculationHardening::expandSpeculationSafeValue(
|
||||
MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI) {
|
||||
MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
|
||||
bool UsesFullSpeculationBarrier) {
|
||||
MachineInstr &MI = *MBBI;
|
||||
unsigned Opcode = MI.getOpcode();
|
||||
bool Is64Bit = true;
|
||||
@ -499,7 +561,7 @@ bool AArch64SpeculationHardening::expandSpeculationSafeValue(
|
||||
// Just remove the SpeculationSafe pseudo's if control flow
|
||||
// miss-speculation isn't happening because we're already inserting barriers
|
||||
// to guarantee that.
|
||||
if (!UseControlFlowSpeculationBarrier) {
|
||||
if (!UseControlFlowSpeculationBarrier && !UsesFullSpeculationBarrier) {
|
||||
unsigned DstReg = MI.getOperand(0).getReg();
|
||||
unsigned SrcReg = MI.getOperand(1).getReg();
|
||||
// Mark this register and all its aliasing registers as needing to be
|
||||
@ -537,7 +599,7 @@ bool AArch64SpeculationHardening::insertCSDB(MachineBasicBlock &MBB,
|
||||
}
|
||||
|
||||
bool AArch64SpeculationHardening::lowerSpeculationSafeValuePseudos(
|
||||
MachineBasicBlock &MBB) {
|
||||
MachineBasicBlock &MBB, bool UsesFullSpeculationBarrier) {
|
||||
bool Modified = false;
|
||||
|
||||
RegsNeedingCSDBBeforeUse.reset();
|
||||
@ -572,15 +634,16 @@ bool AArch64SpeculationHardening::lowerSpeculationSafeValuePseudos(
|
||||
break;
|
||||
}
|
||||
|
||||
if (NeedToEmitBarrier)
|
||||
if (NeedToEmitBarrier && !UsesFullSpeculationBarrier)
|
||||
Modified |= insertCSDB(MBB, MBBI, DL);
|
||||
|
||||
Modified |= expandSpeculationSafeValue(MBB, MBBI);
|
||||
Modified |=
|
||||
expandSpeculationSafeValue(MBB, MBBI, UsesFullSpeculationBarrier);
|
||||
|
||||
MBBI = NMBBI;
|
||||
}
|
||||
|
||||
if (RegsNeedingCSDBBeforeUse.any())
|
||||
if (RegsNeedingCSDBBeforeUse.any() && !UsesFullSpeculationBarrier)
|
||||
Modified |= insertCSDB(MBB, MBBI, DL);
|
||||
|
||||
return Modified;
|
||||
@ -609,7 +672,7 @@ bool AArch64SpeculationHardening::runOnMachineFunction(MachineFunction &MF) {
|
||||
Modified |= slhLoads(MBB);
|
||||
}
|
||||
|
||||
// 2.a Add instrumentation code to function entry and exits.
|
||||
// 2. Add instrumentation code to function entry and exits.
|
||||
LLVM_DEBUG(
|
||||
dbgs()
|
||||
<< "***** AArch64SpeculationHardening - track control flow *****\n");
|
||||
@ -620,17 +683,15 @@ bool AArch64SpeculationHardening::runOnMachineFunction(MachineFunction &MF) {
|
||||
EntryBlocks.push_back(LPI.LandingPadBlock);
|
||||
for (auto Entry : EntryBlocks)
|
||||
insertSPToRegTaintPropagation(
|
||||
Entry, Entry->SkipPHIsLabelsAndDebug(Entry->begin()));
|
||||
*Entry, Entry->SkipPHIsLabelsAndDebug(Entry->begin()));
|
||||
|
||||
// 2.b Add instrumentation code to every basic block.
|
||||
for (auto &MBB : MF)
|
||||
Modified |= instrumentControlFlow(MBB);
|
||||
|
||||
LLVM_DEBUG(dbgs() << "***** AArch64SpeculationHardening - Lowering "
|
||||
"SpeculationSafeValue Pseudos *****\n");
|
||||
// Step 3: Lower SpeculationSafeValue pseudo instructions.
|
||||
for (auto &MBB : MF)
|
||||
Modified |= lowerSpeculationSafeValuePseudos(MBB);
|
||||
// 3. Add instrumentation code to every basic block.
|
||||
for (auto &MBB : MF) {
|
||||
bool UsesFullSpeculationBarrier = false;
|
||||
Modified |= instrumentControlFlow(MBB, UsesFullSpeculationBarrier);
|
||||
Modified |=
|
||||
lowerSpeculationSafeValuePseudos(MBB, UsesFullSpeculationBarrier);
|
||||
}
|
||||
|
||||
return Modified;
|
||||
}
|
||||
|
@ -65,10 +65,7 @@ class MCInstrInfo;
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
static cl::opt<bool>
|
||||
EmitJalrReloc("mips-jalr-reloc", cl::Hidden,
|
||||
cl::desc("MIPS: Emit R_{MICRO}MIPS_JALR relocation with jalr"),
|
||||
cl::init(true));
|
||||
extern cl::opt<bool> EmitJalrReloc;
|
||||
|
||||
namespace {
|
||||
|
||||
|
@ -15,6 +15,13 @@
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
// Note: this option is defined here to be visible from libLLVMMipsAsmParser
|
||||
// and libLLVMMipsCodeGen
|
||||
cl::opt<bool>
|
||||
EmitJalrReloc("mips-jalr-reloc", cl::Hidden,
|
||||
cl::desc("MIPS: Emit R_{MICRO}MIPS_JALR relocation with jalr"),
|
||||
cl::init(true));
|
||||
|
||||
namespace {
|
||||
static const MCPhysReg O32IntRegs[4] = {Mips::A0, Mips::A1, Mips::A2, Mips::A3};
|
||||
|
||||
|
@ -89,7 +89,10 @@ namespace MipsII {
|
||||
MO_GOT_HI16,
|
||||
MO_GOT_LO16,
|
||||
MO_CALL_HI16,
|
||||
MO_CALL_LO16
|
||||
MO_CALL_LO16,
|
||||
|
||||
/// Helper operand used to generate R_MIPS_JALR
|
||||
MO_JALR
|
||||
};
|
||||
|
||||
enum {
|
||||
|
@ -614,8 +614,9 @@ getExprOpValue(const MCExpr *Expr, SmallVectorImpl<MCFixup> &Fixups,
|
||||
llvm_unreachable("Unhandled fixup kind!");
|
||||
break;
|
||||
case MipsMCExpr::MEK_DTPREL:
|
||||
llvm_unreachable("MEK_DTPREL is used for TLS DIEExpr only");
|
||||
break;
|
||||
// MEK_DTPREL is used for marking TLS DIEExpr only
|
||||
// and contains a regular sub-expression.
|
||||
return getExprOpValue(MipsExpr->getSubExpr(), Fixups, STI);
|
||||
case MipsMCExpr::MEK_CALL_HI16:
|
||||
FixupKind = Mips::fixup_Mips_CALL_HI16;
|
||||
break;
|
||||
|
@ -44,8 +44,10 @@ void MipsMCExpr::printImpl(raw_ostream &OS, const MCAsmInfo *MAI) const {
|
||||
llvm_unreachable("MEK_None and MEK_Special are invalid");
|
||||
break;
|
||||
case MEK_DTPREL:
|
||||
llvm_unreachable("MEK_DTPREL is used for TLS DIEExpr only");
|
||||
break;
|
||||
// MEK_DTPREL is used for marking TLS DIEExpr only
|
||||
// and contains a regular sub-expression.
|
||||
getSubExpr()->print(OS, MAI, true);
|
||||
return;
|
||||
case MEK_CALL_HI16:
|
||||
OS << "%call_hi";
|
||||
break;
|
||||
@ -161,7 +163,9 @@ MipsMCExpr::evaluateAsRelocatableImpl(MCValue &Res,
|
||||
case MEK_Special:
|
||||
llvm_unreachable("MEK_None and MEK_Special are invalid");
|
||||
case MEK_DTPREL:
|
||||
llvm_unreachable("MEK_DTPREL is used for TLS DIEExpr only");
|
||||
// MEK_DTPREL is used for marking TLS DIEExpr only
|
||||
// and contains a regular sub-expression.
|
||||
return getSubExpr()->evaluateAsRelocatable(Res, Layout, Fixup);
|
||||
case MEK_DTPREL_HI:
|
||||
case MEK_DTPREL_LO:
|
||||
case MEK_GOT:
|
||||
@ -249,9 +253,6 @@ void MipsMCExpr::fixELFSymbolsInTLSFixups(MCAssembler &Asm) const {
|
||||
case MEK_Special:
|
||||
llvm_unreachable("MEK_None and MEK_Special are invalid");
|
||||
break;
|
||||
case MEK_DTPREL:
|
||||
llvm_unreachable("MEK_DTPREL is used for TLS DIEExpr only");
|
||||
break;
|
||||
case MEK_CALL_HI16:
|
||||
case MEK_CALL_LO16:
|
||||
case MEK_GOT:
|
||||
@ -274,6 +275,7 @@ void MipsMCExpr::fixELFSymbolsInTLSFixups(MCAssembler &Asm) const {
|
||||
if (const MipsMCExpr *E = dyn_cast<const MipsMCExpr>(getSubExpr()))
|
||||
E->fixELFSymbolsInTLSFixups(Asm);
|
||||
break;
|
||||
case MEK_DTPREL:
|
||||
case MEK_DTPREL_HI:
|
||||
case MEK_DTPREL_LO:
|
||||
case MEK_TLSLDM:
|
||||
|
@ -460,6 +460,7 @@ class JALRC16_MMR6_DESC_BASE<string opstr, RegisterOperand RO>
|
||||
let isCall = 1;
|
||||
let hasDelaySlot = 0;
|
||||
let Defs = [RA];
|
||||
let hasPostISelHook = 1;
|
||||
}
|
||||
class JALRC16_MMR6_DESC : JALRC16_MMR6_DESC_BASE<"jalr", GPR32Opnd>;
|
||||
|
||||
|
@ -426,6 +426,7 @@ class JumpLinkRegMM16<string opstr, RegisterOperand RO> :
|
||||
let isCall = 1;
|
||||
let hasDelaySlot = 1;
|
||||
let Defs = [RA];
|
||||
let hasPostISelHook = 1;
|
||||
}
|
||||
|
||||
// 16-bit Jump Reg
|
||||
|
@ -1105,7 +1105,7 @@ def : MipsPat<(select i32:$cond, immz, i32:$f),
|
||||
|
||||
// Pseudo instructions
|
||||
let isCall = 1, isTerminator = 1, isReturn = 1, isBarrier = 1, hasDelaySlot = 1,
|
||||
hasExtraSrcRegAllocReq = 1, isCTI = 1, Defs = [AT] in {
|
||||
hasExtraSrcRegAllocReq = 1, isCTI = 1, Defs = [AT], hasPostISelHook = 1 in {
|
||||
class TailCallRegR6<Instruction JumpInst, Register RT, RegisterOperand RO> :
|
||||
PseudoSE<(outs), (ins RO:$rs), [(MipsTailCall RO:$rs)], II_JR>,
|
||||
PseudoInstExpansion<(JumpInst RT:$rt, RO:$rs)>;
|
||||
|
@ -68,6 +68,8 @@ using namespace llvm;
|
||||
|
||||
#define DEBUG_TYPE "mips-asm-printer"
|
||||
|
||||
extern cl::opt<bool> EmitJalrReloc;
|
||||
|
||||
MipsTargetStreamer &MipsAsmPrinter::getTargetStreamer() const {
|
||||
return static_cast<MipsTargetStreamer &>(*OutStreamer->getTargetStreamer());
|
||||
}
|
||||
@ -148,6 +150,40 @@ void MipsAsmPrinter::emitPseudoIndirectBranch(MCStreamer &OutStreamer,
|
||||
EmitToStreamer(OutStreamer, TmpInst0);
|
||||
}
|
||||
|
||||
// If there is an MO_JALR operand, insert:
|
||||
//
|
||||
// .reloc tmplabel, R_{MICRO}MIPS_JALR, symbol
|
||||
// tmplabel:
|
||||
//
|
||||
// This is an optimization hint for the linker which may then replace
|
||||
// an indirect call with a direct branch.
|
||||
static void emitDirectiveRelocJalr(const MachineInstr &MI,
|
||||
MCContext &OutContext,
|
||||
TargetMachine &TM,
|
||||
MCStreamer &OutStreamer,
|
||||
const MipsSubtarget &Subtarget) {
|
||||
for (unsigned int I = MI.getDesc().getNumOperands(), E = MI.getNumOperands();
|
||||
I < E; ++I) {
|
||||
MachineOperand MO = MI.getOperand(I);
|
||||
if (MO.isMCSymbol() && (MO.getTargetFlags() & MipsII::MO_JALR)) {
|
||||
MCSymbol *Callee = MO.getMCSymbol();
|
||||
if (Callee && !Callee->getName().empty()) {
|
||||
MCSymbol *OffsetLabel = OutContext.createTempSymbol();
|
||||
const MCExpr *OffsetExpr =
|
||||
MCSymbolRefExpr::create(OffsetLabel, OutContext);
|
||||
const MCExpr *CaleeExpr =
|
||||
MCSymbolRefExpr::create(Callee, OutContext);
|
||||
OutStreamer.EmitRelocDirective
|
||||
(*OffsetExpr,
|
||||
Subtarget.inMicroMipsMode() ? "R_MICROMIPS_JALR" : "R_MIPS_JALR",
|
||||
CaleeExpr, SMLoc(), *TM.getMCSubtargetInfo());
|
||||
OutStreamer.EmitLabel(OffsetLabel);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MipsAsmPrinter::EmitInstruction(const MachineInstr *MI) {
|
||||
MipsTargetStreamer &TS = getTargetStreamer();
|
||||
unsigned Opc = MI->getOpcode();
|
||||
@ -207,6 +243,11 @@ void MipsAsmPrinter::EmitInstruction(const MachineInstr *MI) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (EmitJalrReloc &&
|
||||
(MI->isReturn() || MI->isCall() || MI->isIndirectBranch())) {
|
||||
emitDirectiveRelocJalr(*MI, OutContext, TM, *OutStreamer, *Subtarget);
|
||||
}
|
||||
|
||||
MachineBasicBlock::const_instr_iterator I = MI->getIterator();
|
||||
MachineBasicBlock::const_instr_iterator E = MI->getParent()->instr_end();
|
||||
|
||||
|
@ -56,6 +56,7 @@
|
||||
#include "llvm/IR/Type.h"
|
||||
#include "llvm/IR/User.h"
|
||||
#include "llvm/IR/Value.h"
|
||||
#include "llvm/MC/MCContext.h"
|
||||
#include "llvm/MC/MCInstrDesc.h"
|
||||
#include "llvm/MC/MCRegisterInfo.h"
|
||||
#include "llvm/MC/MCSymbol.h"
|
||||
@ -75,6 +76,8 @@
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
extern cl::opt<bool> EmitJalrReloc;
|
||||
|
||||
namespace {
|
||||
|
||||
class MipsFastISel final : public FastISel {
|
||||
@ -1551,6 +1554,16 @@ bool MipsFastISel::fastLowerCall(CallLoweringInfo &CLI) {
|
||||
|
||||
CLI.Call = MIB;
|
||||
|
||||
if (EmitJalrReloc && !Subtarget->inMips16Mode()) {
|
||||
// Attach callee address to the instruction, let asm printer emit
|
||||
// .reloc R_MIPS_JALR.
|
||||
if (Symbol)
|
||||
MIB.addSym(Symbol, MipsII::MO_JALR);
|
||||
else
|
||||
MIB.addSym(FuncInfo.MF->getContext().getOrCreateSymbol(
|
||||
Addr.getGlobalValue()->getName()), MipsII::MO_JALR);
|
||||
}
|
||||
|
||||
// Finish off the call including any return values.
|
||||
return finishCall(CLI, RetVT, NumBytes);
|
||||
}
|
||||
|
@ -57,6 +57,7 @@
|
||||
#include "llvm/IR/GlobalValue.h"
|
||||
#include "llvm/IR/Type.h"
|
||||
#include "llvm/IR/Value.h"
|
||||
#include "llvm/MC/MCContext.h"
|
||||
#include "llvm/MC/MCRegisterInfo.h"
|
||||
#include "llvm/Support/Casting.h"
|
||||
#include "llvm/Support/CodeGen.h"
|
||||
@ -91,6 +92,8 @@ NoZeroDivCheck("mno-check-zero-division", cl::Hidden,
|
||||
cl::desc("MIPS: Don't trap on integer division by zero."),
|
||||
cl::init(false));
|
||||
|
||||
extern cl::opt<bool> EmitJalrReloc;
|
||||
|
||||
static const MCPhysReg Mips64DPRegs[8] = {
|
||||
Mips::D12_64, Mips::D13_64, Mips::D14_64, Mips::D15_64,
|
||||
Mips::D16_64, Mips::D17_64, Mips::D18_64, Mips::D19_64
|
||||
@ -2879,6 +2882,54 @@ getOpndList(SmallVectorImpl<SDValue> &Ops,
|
||||
Ops.push_back(InFlag);
|
||||
}
|
||||
|
||||
void MipsTargetLowering::AdjustInstrPostInstrSelection(MachineInstr &MI,
|
||||
SDNode *Node) const {
|
||||
switch (MI.getOpcode()) {
|
||||
default:
|
||||
return;
|
||||
case Mips::JALR:
|
||||
case Mips::JALRPseudo:
|
||||
case Mips::JALR64:
|
||||
case Mips::JALR64Pseudo:
|
||||
case Mips::JALR16_MM:
|
||||
case Mips::JALRC16_MMR6:
|
||||
case Mips::TAILCALLREG:
|
||||
case Mips::TAILCALLREG64:
|
||||
case Mips::TAILCALLR6REG:
|
||||
case Mips::TAILCALL64R6REG:
|
||||
case Mips::TAILCALLREG_MM:
|
||||
case Mips::TAILCALLREG_MMR6: {
|
||||
if (!EmitJalrReloc ||
|
||||
Subtarget.inMips16Mode() ||
|
||||
!isPositionIndependent() ||
|
||||
Node->getNumOperands() < 1 ||
|
||||
Node->getOperand(0).getNumOperands() < 2) {
|
||||
return;
|
||||
}
|
||||
// We are after the callee address, set by LowerCall().
|
||||
// If added to MI, asm printer will emit .reloc R_MIPS_JALR for the
|
||||
// symbol.
|
||||
const SDValue TargetAddr = Node->getOperand(0).getOperand(1);
|
||||
StringRef Sym;
|
||||
if (const GlobalAddressSDNode *G =
|
||||
dyn_cast_or_null<const GlobalAddressSDNode>(TargetAddr)) {
|
||||
Sym = G->getGlobal()->getName();
|
||||
}
|
||||
else if (const ExternalSymbolSDNode *ES =
|
||||
dyn_cast_or_null<const ExternalSymbolSDNode>(TargetAddr)) {
|
||||
Sym = ES->getSymbol();
|
||||
}
|
||||
|
||||
if (Sym.empty())
|
||||
return;
|
||||
|
||||
MachineFunction *MF = MI.getParent()->getParent();
|
||||
MCSymbol *S = MF->getContext().getOrCreateSymbol(Sym);
|
||||
MI.addOperand(MachineOperand::CreateMCSymbol(S, MipsII::MO_JALR));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// LowerCall - functions arguments are copied from virtual regs to
|
||||
/// (physical regs)/(stack frame), CALLSEQ_START and CALLSEQ_END are emitted.
|
||||
SDValue
|
||||
@ -2930,7 +2981,7 @@ MipsTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
|
||||
// the maximum out going argument area (including the reserved area), and
|
||||
// preallocates the stack space on entrance to the caller.
|
||||
//
|
||||
// FIXME: We should do the same for efficency and space.
|
||||
// FIXME: We should do the same for efficiency and space.
|
||||
|
||||
// Note: The check on the calling convention below must match
|
||||
// MipsABIInfo::GetCalleeAllocdArgSizeInBytes().
|
||||
|
@ -341,6 +341,9 @@ class TargetRegisterClass;
|
||||
EmitInstrWithCustomInserter(MachineInstr &MI,
|
||||
MachineBasicBlock *MBB) const override;
|
||||
|
||||
void AdjustInstrPostInstrSelection(MachineInstr &MI,
|
||||
SDNode *Node) const override;
|
||||
|
||||
void HandleByVal(CCState *, unsigned &, unsigned) const override;
|
||||
|
||||
unsigned getRegisterByName(const char* RegName, EVT VT,
|
||||
|
@ -653,6 +653,16 @@ MipsInstrInfo::genInstrWithNewOpc(unsigned NewOpc,
|
||||
|
||||
MIB.addImm(0);
|
||||
|
||||
// If I has an MCSymbol operand (used by asm printer, to emit R_MIPS_JALR),
|
||||
// add it to the new instruction.
|
||||
for (unsigned J = I->getDesc().getNumOperands(), E = I->getNumOperands();
|
||||
J < E; ++J) {
|
||||
const MachineOperand &MO = I->getOperand(J);
|
||||
if (MO.isMCSymbol() && (MO.getTargetFlags() & MipsII::MO_JALR))
|
||||
MIB.addSym(MO.getMCSymbol(), MipsII::MO_JALR);
|
||||
}
|
||||
|
||||
|
||||
} else {
|
||||
for (unsigned J = 0, E = I->getDesc().getNumOperands(); J < E; ++J) {
|
||||
if (BranchWithZeroOperand && (unsigned)ZeroOperandPosition == J)
|
||||
@ -825,7 +835,8 @@ MipsInstrInfo::getSerializableDirectMachineOperandTargetFlags() const {
|
||||
{MO_GOT_HI16, "mips-got-hi16"},
|
||||
{MO_GOT_LO16, "mips-got-lo16"},
|
||||
{MO_CALL_HI16, "mips-call-hi16"},
|
||||
{MO_CALL_LO16, "mips-call-lo16"}
|
||||
{MO_CALL_LO16, "mips-call-lo16"},
|
||||
{MO_JALR, "mips-jalr"}
|
||||
};
|
||||
return makeArrayRef(Flags);
|
||||
}
|
||||
|
@ -1623,11 +1623,15 @@ let isCall=1, hasDelaySlot=1, isCTI=1, Defs = [RA] in {
|
||||
class JumpLinkRegPseudo<RegisterOperand RO, Instruction JALRInst,
|
||||
Register RetReg, RegisterOperand ResRO = RO>:
|
||||
PseudoSE<(outs), (ins RO:$rs), [(MipsJmpLink RO:$rs)], II_JALR>,
|
||||
PseudoInstExpansion<(JALRInst RetReg, ResRO:$rs)>;
|
||||
PseudoInstExpansion<(JALRInst RetReg, ResRO:$rs)> {
|
||||
let hasPostISelHook = 1;
|
||||
}
|
||||
|
||||
class JumpLinkReg<string opstr, RegisterOperand RO>:
|
||||
InstSE<(outs RO:$rd), (ins RO:$rs), !strconcat(opstr, "\t$rd, $rs"),
|
||||
[], II_JALR, FrmR, opstr>;
|
||||
[], II_JALR, FrmR, opstr> {
|
||||
let hasPostISelHook = 1;
|
||||
}
|
||||
|
||||
class BGEZAL_FT<string opstr, DAGOperand opnd,
|
||||
RegisterOperand RO> :
|
||||
@ -1646,7 +1650,9 @@ let isCall = 1, isTerminator = 1, isReturn = 1, isBarrier = 1, hasDelaySlot = 1,
|
||||
|
||||
class TailCallReg<Instruction JumpInst, RegisterOperand RO> :
|
||||
PseudoSE<(outs), (ins RO:$rs), [(MipsTailCall RO:$rs)], II_JR>,
|
||||
PseudoInstExpansion<(JumpInst RO:$rs)>;
|
||||
PseudoInstExpansion<(JumpInst RO:$rs)> {
|
||||
let hasPostISelHook = 1;
|
||||
}
|
||||
}
|
||||
|
||||
class BAL_BR_Pseudo<Instruction RealInst, DAGOperand opnd> :
|
||||
|
@ -117,6 +117,8 @@ MCOperand MipsMCInstLower::LowerSymbolOperand(const MachineOperand &MO,
|
||||
case MipsII::MO_CALL_LO16:
|
||||
TargetKind = MipsMCExpr::MEK_CALL_LO16;
|
||||
break;
|
||||
case MipsII::MO_JALR:
|
||||
return MCOperand();
|
||||
}
|
||||
|
||||
switch (MOTy) {
|
||||
|
@ -27,6 +27,14 @@ using namespace llvm;
|
||||
|
||||
#define DEBUG_TYPE "x86-discriminate-memops"
|
||||
|
||||
static cl::opt<bool> EnableDiscriminateMemops(
|
||||
DEBUG_TYPE, cl::init(false),
|
||||
cl::desc("Generate unique debug info for each instruction with a memory "
|
||||
"operand. Should be enabled for profile-drived cache prefetching, "
|
||||
"both in the build of the binary being profiled, as well as in "
|
||||
"the build of the binary consuming the profile."),
|
||||
cl::Hidden);
|
||||
|
||||
namespace {
|
||||
|
||||
using Location = std::pair<StringRef, unsigned>;
|
||||
@ -67,6 +75,9 @@ char X86DiscriminateMemOps::ID = 0;
|
||||
X86DiscriminateMemOps::X86DiscriminateMemOps() : MachineFunctionPass(ID) {}
|
||||
|
||||
bool X86DiscriminateMemOps::runOnMachineFunction(MachineFunction &MF) {
|
||||
if (!EnableDiscriminateMemops)
|
||||
return false;
|
||||
|
||||
DISubprogram *FDI = MF.getFunction().getSubprogram();
|
||||
if (!FDI || !FDI->getUnit()->getDebugInfoForProfiling())
|
||||
return false;
|
||||
|
@ -34,7 +34,8 @@ using namespace sampleprof;
|
||||
|
||||
static cl::opt<std::string>
|
||||
PrefetchHintsFile("prefetch-hints-file",
|
||||
cl::desc("Path to the prefetch hints profile."),
|
||||
cl::desc("Path to the prefetch hints profile. See also "
|
||||
"-x86-discriminate-memops"),
|
||||
cl::Hidden);
|
||||
namespace {
|
||||
|
||||
|
@ -249,6 +249,8 @@ void FunctionImportGlobalProcessing::processGlobalForThinLTO(GlobalValue &GV) {
|
||||
bool DoPromote = false;
|
||||
if (GV.hasLocalLinkage() &&
|
||||
((DoPromote = shouldPromoteLocalToGlobal(&GV)) || isPerformingImport())) {
|
||||
// Save the original name string before we rename GV below.
|
||||
auto Name = GV.getName().str();
|
||||
// Once we change the name or linkage it is difficult to determine
|
||||
// again whether we should promote since shouldPromoteLocalToGlobal needs
|
||||
// to locate the summary (based on GUID from name and linkage). Therefore,
|
||||
@ -257,6 +259,12 @@ void FunctionImportGlobalProcessing::processGlobalForThinLTO(GlobalValue &GV) {
|
||||
GV.setLinkage(getLinkage(&GV, DoPromote));
|
||||
if (!GV.hasLocalLinkage())
|
||||
GV.setVisibility(GlobalValue::HiddenVisibility);
|
||||
|
||||
// If we are renaming a COMDAT leader, ensure that we record the COMDAT
|
||||
// for later renaming as well. This is required for COFF.
|
||||
if (const auto *C = GV.getComdat())
|
||||
if (C->getName() == Name)
|
||||
RenamedComdats.try_emplace(C, M.getOrInsertComdat(GV.getName()));
|
||||
} else
|
||||
GV.setLinkage(getLinkage(&GV, /* DoPromote */ false));
|
||||
|
||||
@ -281,6 +289,16 @@ void FunctionImportGlobalProcessing::processGlobalsForThinLTO() {
|
||||
processGlobalForThinLTO(SF);
|
||||
for (GlobalAlias &GA : M.aliases())
|
||||
processGlobalForThinLTO(GA);
|
||||
|
||||
// Replace any COMDATS that required renaming (because the COMDAT leader was
|
||||
// promoted and renamed).
|
||||
if (!RenamedComdats.empty())
|
||||
for (auto &GO : M.global_objects())
|
||||
if (auto *C = GO.getComdat()) {
|
||||
auto Replacement = RenamedComdats.find(C);
|
||||
if (Replacement != RenamedComdats.end())
|
||||
GO.setComdat(Replacement->second);
|
||||
}
|
||||
}
|
||||
|
||||
bool FunctionImportGlobalProcessing::run() {
|
||||
|
@ -217,7 +217,10 @@ static Optional<bool> getOptionalBoolLoopAttribute(const Loop *TheLoop,
|
||||
// When the value is absent it is interpreted as 'attribute set'.
|
||||
return true;
|
||||
case 2:
|
||||
return mdconst::extract_or_null<ConstantInt>(MD->getOperand(1).get());
|
||||
if (ConstantInt *IntMD =
|
||||
mdconst::extract_or_null<ConstantInt>(MD->getOperand(1).get()))
|
||||
return IntMD->getZExtValue();
|
||||
return true;
|
||||
}
|
||||
llvm_unreachable("unexpected number of options");
|
||||
}
|
||||
@ -376,17 +379,17 @@ TransformationMode llvm::hasVectorizeTransformation(Loop *L) {
|
||||
Optional<int> InterleaveCount =
|
||||
getOptionalIntLoopAttribute(L, "llvm.loop.interleave.count");
|
||||
|
||||
if (Enable == true) {
|
||||
// 'Forcing' vector width and interleave count to one effectively disables
|
||||
// this tranformation.
|
||||
if (VectorizeWidth == 1 && InterleaveCount == 1)
|
||||
return TM_SuppressedByUser;
|
||||
return TM_ForcedByUser;
|
||||
}
|
||||
// 'Forcing' vector width and interleave count to one effectively disables
|
||||
// this tranformation.
|
||||
if (Enable == true && VectorizeWidth == 1 && InterleaveCount == 1)
|
||||
return TM_SuppressedByUser;
|
||||
|
||||
if (getBooleanLoopAttribute(L, "llvm.loop.isvectorized"))
|
||||
return TM_Disable;
|
||||
|
||||
if (Enable == true)
|
||||
return TM_ForcedByUser;
|
||||
|
||||
if (VectorizeWidth == 1 && InterleaveCount == 1)
|
||||
return TM_Disable;
|
||||
|
||||
|
@ -33,7 +33,7 @@ BUILTIN(__builtin_arm_clrex, "v", "")
|
||||
|
||||
// Bit manipulation
|
||||
BUILTIN(__builtin_arm_rbit, "UiUi", "nc")
|
||||
BUILTIN(__builtin_arm_rbit64, "LUiLUi", "nc")
|
||||
BUILTIN(__builtin_arm_rbit64, "WUiWUi", "nc")
|
||||
|
||||
// HINT
|
||||
BUILTIN(__builtin_arm_nop, "v", "")
|
||||
@ -50,8 +50,8 @@ BUILTIN(__builtin_arm_crc32h, "UiUiUs", "nc")
|
||||
BUILTIN(__builtin_arm_crc32ch, "UiUiUs", "nc")
|
||||
BUILTIN(__builtin_arm_crc32w, "UiUiUi", "nc")
|
||||
BUILTIN(__builtin_arm_crc32cw, "UiUiUi", "nc")
|
||||
BUILTIN(__builtin_arm_crc32d, "UiUiLUi", "nc")
|
||||
BUILTIN(__builtin_arm_crc32cd, "UiUiLUi", "nc")
|
||||
BUILTIN(__builtin_arm_crc32d, "UiUiWUi", "nc")
|
||||
BUILTIN(__builtin_arm_crc32cd, "UiUiWUi", "nc")
|
||||
|
||||
// Memory barrier
|
||||
BUILTIN(__builtin_arm_dmb, "vUi", "nc")
|
||||
@ -63,10 +63,10 @@ BUILTIN(__builtin_arm_prefetch, "vvC*UiUiUiUi", "nc")
|
||||
|
||||
// System Registers
|
||||
BUILTIN(__builtin_arm_rsr, "UicC*", "nc")
|
||||
BUILTIN(__builtin_arm_rsr64, "LUicC*", "nc")
|
||||
BUILTIN(__builtin_arm_rsr64, "WUicC*", "nc")
|
||||
BUILTIN(__builtin_arm_rsrp, "v*cC*", "nc")
|
||||
BUILTIN(__builtin_arm_wsr, "vcC*Ui", "nc")
|
||||
BUILTIN(__builtin_arm_wsr64, "vcC*LUi", "nc")
|
||||
BUILTIN(__builtin_arm_wsr64, "vcC*WUi", "nc")
|
||||
BUILTIN(__builtin_arm_wsrp, "vcC*vC*", "nc")
|
||||
|
||||
// MSVC
|
||||
|
@ -96,7 +96,7 @@ FEATURE(objc_arc, LangOpts.ObjCAutoRefCount)
|
||||
FEATURE(objc_arc_fields, true)
|
||||
FEATURE(objc_arc_weak, LangOpts.ObjCWeak)
|
||||
FEATURE(objc_default_synthesize_properties, LangOpts.ObjC)
|
||||
FEATURE(objc_fixed_enum, true)
|
||||
FEATURE(objc_fixed_enum, LangOpts.ObjC)
|
||||
FEATURE(objc_instancetype, LangOpts.ObjC)
|
||||
FEATURE(objc_kindof, LangOpts.ObjC)
|
||||
FEATURE(objc_modules, LangOpts.ObjC && LangOpts.Modules)
|
||||
|
@ -70,15 +70,14 @@ class FileEntry {
|
||||
bool IsNamedPipe;
|
||||
bool InPCH;
|
||||
bool IsValid; // Is this \c FileEntry initialized and valid?
|
||||
bool DeferredOpen; // Created by getFile(OpenFile=0); may open later.
|
||||
|
||||
/// The open file, if it is owned by the \p FileEntry.
|
||||
mutable std::unique_ptr<llvm::vfs::File> File;
|
||||
|
||||
public:
|
||||
FileEntry()
|
||||
: UniqueID(0, 0), IsNamedPipe(false), InPCH(false), IsValid(false),
|
||||
DeferredOpen(false) {}
|
||||
: UniqueID(0, 0), IsNamedPipe(false), InPCH(false), IsValid(false)
|
||||
{}
|
||||
|
||||
FileEntry(const FileEntry &) = delete;
|
||||
FileEntry &operator=(const FileEntry &) = delete;
|
||||
|
@ -64,6 +64,7 @@ class TargetInfo : public RefCountedBase<TargetInfo> {
|
||||
bool HasLegalHalfType; // True if the backend supports operations on the half
|
||||
// LLVM IR type.
|
||||
bool HasFloat128;
|
||||
bool HasFloat16;
|
||||
unsigned char PointerWidth, PointerAlign;
|
||||
unsigned char BoolWidth, BoolAlign;
|
||||
unsigned char IntWidth, IntAlign;
|
||||
@ -517,6 +518,9 @@ class TargetInfo : public RefCountedBase<TargetInfo> {
|
||||
/// Determine whether the __float128 type is supported on this target.
|
||||
virtual bool hasFloat128Type() const { return HasFloat128; }
|
||||
|
||||
/// Determine whether the _Float16 type is supported on this target.
|
||||
virtual bool hasFloat16Type() const { return HasFloat16; }
|
||||
|
||||
/// Return the alignment that is suitable for storing any
|
||||
/// object with a fundamental alignment requirement.
|
||||
unsigned getSuitableAlign() const { return SuitableAlign; }
|
||||
|
@ -2418,6 +2418,14 @@ def modd_spreg : Flag<["-"], "modd-spreg">, Group<m_mips_Features_Group>,
|
||||
def mno_odd_spreg : Flag<["-"], "mno-odd-spreg">, Group<m_mips_Features_Group>,
|
||||
HelpText<"Disable odd single-precision floating point registers">,
|
||||
Flags<[HelpHidden]>;
|
||||
def mrelax_pic_calls : Flag<["-"], "mrelax-pic-calls">,
|
||||
Group<m_mips_Features_Group>,
|
||||
HelpText<"Try turning PIC calls (j{al}r{c} $25) into direct calls "
|
||||
"(MIPS only)">, Flags<[HelpHidden]>;
|
||||
def mno_relax_pic_calls : Flag<["-"], "mno-relax-pic-calls">,
|
||||
Group<m_mips_Features_Group>,
|
||||
HelpText<"Do not try turning PIC calls (j{al}r{c} $25) into direct calls "
|
||||
"(MIPS only)">, Flags<[HelpHidden]>;
|
||||
def mglibc : Flag<["-"], "mglibc">, Group<m_libc_Group>, Flags<[HelpHidden]>;
|
||||
def muclibc : Flag<["-"], "muclibc">, Group<m_libc_Group>, Flags<[HelpHidden]>;
|
||||
def module_file_info : Flag<["-"], "module-file-info">, Flags<[DriverOption,CC1Option]>, Group<Action_Group>,
|
||||
|
@ -61,6 +61,10 @@ ArgumentsAdjuster getInsertArgumentAdjuster(
|
||||
const char *Extra,
|
||||
ArgumentInsertPosition Pos = ArgumentInsertPosition::END);
|
||||
|
||||
/// Gets an argument adjuster which strips plugin related command line
|
||||
/// arguments.
|
||||
ArgumentsAdjuster getStripPluginsAdjuster();
|
||||
|
||||
/// Gets an argument adjuster which adjusts the arguments in sequence
|
||||
/// with the \p First adjuster and then with the \p Second one.
|
||||
ArgumentsAdjuster combineAdjusters(ArgumentsAdjuster First,
|
||||
|
@ -189,21 +189,15 @@ const FileEntry *FileManager::getFile(StringRef Filename, bool openFile,
|
||||
*SeenFileEntries.insert(std::make_pair(Filename, nullptr)).first;
|
||||
|
||||
// See if there is already an entry in the map.
|
||||
if (NamedFileEnt.second) {
|
||||
if (NamedFileEnt.second == NON_EXISTENT_FILE)
|
||||
return nullptr;
|
||||
// Entry exists: return it *unless* it wasn't opened and open is requested.
|
||||
if (!(NamedFileEnt.second->DeferredOpen && openFile))
|
||||
return NamedFileEnt.second;
|
||||
// We previously stat()ed the file, but didn't open it: do that below.
|
||||
// FIXME: the below does other redundant work too (stats the dir and file).
|
||||
} else {
|
||||
// By default, initialize it to invalid.
|
||||
NamedFileEnt.second = NON_EXISTENT_FILE;
|
||||
}
|
||||
if (NamedFileEnt.second)
|
||||
return NamedFileEnt.second == NON_EXISTENT_FILE ? nullptr
|
||||
: NamedFileEnt.second;
|
||||
|
||||
++NumFileCacheMisses;
|
||||
|
||||
// By default, initialize it to invalid.
|
||||
NamedFileEnt.second = NON_EXISTENT_FILE;
|
||||
|
||||
// Get the null-terminated file name as stored as the key of the
|
||||
// SeenFileEntries map.
|
||||
StringRef InterndFileName = NamedFileEnt.first();
|
||||
@ -241,7 +235,6 @@ const FileEntry *FileManager::getFile(StringRef Filename, bool openFile,
|
||||
// It exists. See if we have already opened a file with the same inode.
|
||||
// This occurs when one dir is symlinked to another, for example.
|
||||
FileEntry &UFE = UniqueRealFiles[Data.UniqueID];
|
||||
UFE.DeferredOpen = !openFile;
|
||||
|
||||
NamedFileEnt.second = &UFE;
|
||||
|
||||
@ -258,15 +251,6 @@ const FileEntry *FileManager::getFile(StringRef Filename, bool openFile,
|
||||
InterndFileName = NamedFileEnt.first().data();
|
||||
}
|
||||
|
||||
// If we opened the file for the first time, record the resulting info.
|
||||
// Do this even if the cache entry was valid, maybe we didn't previously open.
|
||||
if (F && !UFE.File) {
|
||||
if (auto PathName = F->getName())
|
||||
fillRealPathName(&UFE, *PathName);
|
||||
UFE.File = std::move(F);
|
||||
assert(!UFE.DeferredOpen && "we just opened it!");
|
||||
}
|
||||
|
||||
if (UFE.isValid()) { // Already have an entry with this inode, return it.
|
||||
|
||||
// FIXME: this hack ensures that if we look up a file by a virtual path in
|
||||
@ -297,9 +281,13 @@ const FileEntry *FileManager::getFile(StringRef Filename, bool openFile,
|
||||
UFE.UniqueID = Data.UniqueID;
|
||||
UFE.IsNamedPipe = Data.IsNamedPipe;
|
||||
UFE.InPCH = Data.InPCH;
|
||||
UFE.File = std::move(F);
|
||||
UFE.IsValid = true;
|
||||
// Note File and DeferredOpen were initialized above.
|
||||
|
||||
if (UFE.File) {
|
||||
if (auto PathName = UFE.File->getName())
|
||||
fillRealPathName(&UFE, *PathName);
|
||||
}
|
||||
return &UFE;
|
||||
}
|
||||
|
||||
@ -371,7 +359,6 @@ FileManager::getVirtualFile(StringRef Filename, off_t Size,
|
||||
UFE->UID = NextFileUID++;
|
||||
UFE->IsValid = true;
|
||||
UFE->File.reset();
|
||||
UFE->DeferredOpen = false;
|
||||
return UFE;
|
||||
}
|
||||
|
||||
|
@ -35,6 +35,7 @@ TargetInfo::TargetInfo(const llvm::Triple &T) : TargetOpts(), Triple(T) {
|
||||
NoAsmVariants = false;
|
||||
HasLegalHalfType = false;
|
||||
HasFloat128 = false;
|
||||
HasFloat16 = false;
|
||||
PointerWidth = PointerAlign = 32;
|
||||
BoolWidth = BoolAlign = 8;
|
||||
IntWidth = IntAlign = 32;
|
||||
|
@ -570,19 +570,27 @@ TargetInfo *AllocateTarget(const llvm::Triple &Triple,
|
||||
Triple.getVendor() != llvm::Triple::UnknownVendor ||
|
||||
!Triple.isOSBinFormatWasm())
|
||||
return nullptr;
|
||||
if (Triple.getOS() != llvm::Triple::UnknownOS &&
|
||||
Triple.getOS() != llvm::Triple::WASI)
|
||||
return nullptr;
|
||||
return new WebAssemblyOSTargetInfo<WebAssembly32TargetInfo>(Triple, Opts);
|
||||
switch (Triple.getOS()) {
|
||||
case llvm::Triple::WASI:
|
||||
return new WASITargetInfo<WebAssembly32TargetInfo>(Triple, Opts);
|
||||
case llvm::Triple::UnknownOS:
|
||||
return new WebAssemblyOSTargetInfo<WebAssembly32TargetInfo>(Triple, Opts);
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
case llvm::Triple::wasm64:
|
||||
if (Triple.getSubArch() != llvm::Triple::NoSubArch ||
|
||||
Triple.getVendor() != llvm::Triple::UnknownVendor ||
|
||||
!Triple.isOSBinFormatWasm())
|
||||
return nullptr;
|
||||
if (Triple.getOS() != llvm::Triple::UnknownOS &&
|
||||
Triple.getOS() != llvm::Triple::WASI)
|
||||
return nullptr;
|
||||
return new WebAssemblyOSTargetInfo<WebAssembly64TargetInfo>(Triple, Opts);
|
||||
switch (Triple.getOS()) {
|
||||
case llvm::Triple::WASI:
|
||||
return new WASITargetInfo<WebAssembly64TargetInfo>(Triple, Opts);
|
||||
case llvm::Triple::UnknownOS:
|
||||
return new WebAssemblyOSTargetInfo<WebAssembly64TargetInfo>(Triple, Opts);
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
case llvm::Triple::renderscript32:
|
||||
return new LinuxTargetInfo<RenderScript32TargetInfo>(Triple, Opts);
|
||||
|
@ -50,6 +50,7 @@ AArch64TargetInfo::AArch64TargetInfo(const llvm::Triple &Triple,
|
||||
|
||||
// All AArch64 implementations support ARMv8 FP, which makes half a legal type.
|
||||
HasLegalHalfType = true;
|
||||
HasFloat16 = true;
|
||||
|
||||
LongWidth = LongAlign = PointerWidth = PointerAlign = 64;
|
||||
MaxVectorAlign = 128;
|
||||
|
@ -397,6 +397,7 @@ bool ARMTargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
|
||||
SoftFloat = SoftFloatABI = false;
|
||||
HWDiv = 0;
|
||||
DotProd = 0;
|
||||
HasFloat16 = true;
|
||||
|
||||
// This does not diagnose illegal cases like having both
|
||||
// "+vfpv2" and "+vfpv3" or having "+neon" and "+fp-only-sp".
|
||||
|
@ -764,8 +764,9 @@ class LLVM_LIBRARY_VISIBILITY FuchsiaTargetInfo : public OSTargetInfo<Target> {
|
||||
template <typename Target>
|
||||
class LLVM_LIBRARY_VISIBILITY WebAssemblyOSTargetInfo
|
||||
: public OSTargetInfo<Target> {
|
||||
protected:
|
||||
void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
|
||||
MacroBuilder &Builder) const final {
|
||||
MacroBuilder &Builder) const {
|
||||
// A common platform macro.
|
||||
if (Opts.POSIXThreads)
|
||||
Builder.defineMacro("_REENTRANT");
|
||||
@ -783,6 +784,21 @@ class LLVM_LIBRARY_VISIBILITY WebAssemblyOSTargetInfo
|
||||
}
|
||||
};
|
||||
|
||||
// WASI target
|
||||
template <typename Target>
|
||||
class LLVM_LIBRARY_VISIBILITY WASITargetInfo
|
||||
: public WebAssemblyOSTargetInfo<Target> {
|
||||
void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
|
||||
MacroBuilder &Builder) const final {
|
||||
WebAssemblyOSTargetInfo<Target>::getOSDefines(Opts, Triple, Builder);
|
||||
Builder.defineMacro("__wasi__");
|
||||
}
|
||||
|
||||
public:
|
||||
explicit WASITargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
|
||||
: WebAssemblyOSTargetInfo<Target>(Triple, Opts) {}
|
||||
};
|
||||
|
||||
} // namespace targets
|
||||
} // namespace clang
|
||||
#endif // LLVM_CLANG_LIB_BASIC_TARGETS_OSTARGETS_H
|
||||
|
@ -48,6 +48,7 @@ class LLVM_LIBRARY_VISIBILITY SPIRTargetInfo : public TargetInfo {
|
||||
AddrSpaceMap = &SPIRAddrSpaceMap;
|
||||
UseAddrSpaceMapMangling = true;
|
||||
HasLegalHalfType = true;
|
||||
HasFloat16 = true;
|
||||
// Define available target features
|
||||
// These must be defined in sorted order!
|
||||
NoAsmVariants = true;
|
||||
|
@ -1716,6 +1716,14 @@ void Clang::AddMIPSTargetArgs(const ArgList &Args,
|
||||
} else
|
||||
D.Diag(diag::warn_target_unsupported_compact_branches) << CPUName;
|
||||
}
|
||||
|
||||
if (Arg *A = Args.getLastArg(options::OPT_mrelax_pic_calls,
|
||||
options::OPT_mno_relax_pic_calls)) {
|
||||
if (A->getOption().matches(options::OPT_mno_relax_pic_calls)) {
|
||||
CmdArgs.push_back("-mllvm");
|
||||
CmdArgs.push_back("-mips-jalr-reloc=0");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Clang::AddPPCTargetArgs(const ArgList &Args,
|
||||
|
@ -256,6 +256,13 @@ void netbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA,
|
||||
bool NeedsXRayDeps = addXRayRuntime(ToolChain, Args, CmdArgs);
|
||||
AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA);
|
||||
|
||||
const SanitizerArgs &SanArgs = ToolChain.getSanitizerArgs();
|
||||
if (SanArgs.needsSharedRt()) {
|
||||
CmdArgs.push_back("-rpath");
|
||||
CmdArgs.push_back(Args.MakeArgString(
|
||||
ToolChain.getCompilerRTPath().c_str()));
|
||||
}
|
||||
|
||||
unsigned Major, Minor, Micro;
|
||||
ToolChain.getTriple().getOSVersion(Major, Minor, Micro);
|
||||
bool useLibgcc = true;
|
||||
|
@ -14470,7 +14470,7 @@ half16 __ovld __cnfn shuffle2(half16 x, half16 y, ushort16 mask);
|
||||
#if __OPENCL_C_VERSION__ >= CL_VERSION_1_2
|
||||
// OpenCL v1.2 s6.12.13, v2.0 s6.13.13 - printf
|
||||
|
||||
int printf(__constant const char* st, ...) __attribute__((format(printf, 1, 2)));
|
||||
int printf(__constant const char* st, ...);
|
||||
#endif
|
||||
|
||||
// OpenCL v1.1 s6.11.3, v1.2 s6.12.14, v2.0 s6.13.14 - Image Read and Write Functions
|
||||
|
@ -617,10 +617,11 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling,
|
||||
if (isHalf || isFloat || isLong || isFloat128)
|
||||
break; // HF, FF, LF, QF invalid.
|
||||
|
||||
if (s + 2 < ThisTokEnd && s[1] == '1' && s[2] == '6') {
|
||||
s += 2; // success, eat up 2 characters.
|
||||
isFloat16 = true;
|
||||
continue;
|
||||
if (PP.getTargetInfo().hasFloat16Type() && s + 2 < ThisTokEnd &&
|
||||
s[1] == '1' && s[2] == '6') {
|
||||
s += 2; // success, eat up 2 characters.
|
||||
isFloat16 = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
isFloat = true;
|
||||
|
@ -681,7 +681,8 @@ QualType clang::getDeclUsageType(ASTContext &C, const NamedDecl *ND) {
|
||||
T = Property->getType();
|
||||
else if (const auto *Value = dyn_cast<ValueDecl>(ND))
|
||||
T = Value->getType();
|
||||
else
|
||||
|
||||
if (T.isNull())
|
||||
return QualType();
|
||||
|
||||
// Dig through references, function pointers, and block pointers to
|
||||
|
@ -1301,6 +1301,10 @@ static DeclAccessPair findDecomposableBaseClass(Sema &S, SourceLocation Loc,
|
||||
static bool checkMemberDecomposition(Sema &S, ArrayRef<BindingDecl*> Bindings,
|
||||
ValueDecl *Src, QualType DecompType,
|
||||
const CXXRecordDecl *OrigRD) {
|
||||
if (S.RequireCompleteType(Src->getLocation(), DecompType,
|
||||
diag::err_incomplete_type))
|
||||
return true;
|
||||
|
||||
CXXCastPath BasePath;
|
||||
DeclAccessPair BasePair =
|
||||
findDecomposableBaseClass(S, Src->getLocation(), OrigRD, BasePath);
|
||||
@ -5886,9 +5890,6 @@ static bool canPassInRegisters(Sema &S, CXXRecordDecl *D,
|
||||
if (D->isDependentType() || D->isInvalidDecl())
|
||||
return false;
|
||||
|
||||
if (D->hasAttr<TrivialABIAttr>())
|
||||
return true;
|
||||
|
||||
// Clang <= 4 used the pre-C++11 rule, which ignores move operations.
|
||||
// The PS4 platform ABI follows the behavior of Clang 3.2.
|
||||
if (CCK == TargetInfo::CCK_ClangABI4OrPS4)
|
||||
|
@ -738,33 +738,20 @@ ExprResult Sema::DefaultArgumentPromotion(Expr *E) {
|
||||
return ExprError();
|
||||
E = Res.get();
|
||||
|
||||
QualType ScalarTy = Ty;
|
||||
unsigned NumElts = 0;
|
||||
if (const ExtVectorType *VecTy = Ty->getAs<ExtVectorType>()) {
|
||||
NumElts = VecTy->getNumElements();
|
||||
ScalarTy = VecTy->getElementType();
|
||||
}
|
||||
|
||||
// If this is a 'float' or '__fp16' (CVR qualified or typedef)
|
||||
// promote to double.
|
||||
// Note that default argument promotion applies only to float (and
|
||||
// half/fp16); it does not apply to _Float16.
|
||||
const BuiltinType *BTy = ScalarTy->getAs<BuiltinType>();
|
||||
const BuiltinType *BTy = Ty->getAs<BuiltinType>();
|
||||
if (BTy && (BTy->getKind() == BuiltinType::Half ||
|
||||
BTy->getKind() == BuiltinType::Float)) {
|
||||
if (getLangOpts().OpenCL &&
|
||||
!getOpenCLOptions().isEnabled("cl_khr_fp64")) {
|
||||
if (BTy->getKind() == BuiltinType::Half) {
|
||||
QualType Ty = Context.FloatTy;
|
||||
if (NumElts != 0)
|
||||
Ty = Context.getExtVectorType(Ty, NumElts);
|
||||
E = ImpCastExprToType(E, Ty, CK_FloatingCast).get();
|
||||
}
|
||||
if (BTy->getKind() == BuiltinType::Half) {
|
||||
E = ImpCastExprToType(E, Context.FloatTy, CK_FloatingCast).get();
|
||||
}
|
||||
} else {
|
||||
QualType Ty = Context.DoubleTy;
|
||||
if (NumElts != 0)
|
||||
Ty = Context.getExtVectorType(Ty, NumElts);
|
||||
E = ImpCastExprToType(E, Ty, CK_FloatingCast).get();
|
||||
E = ImpCastExprToType(E, Context.DoubleTy, CK_FloatingCast).get();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6309,7 +6309,7 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
|
||||
// -- a predefined __func__ variable
|
||||
if (auto *E = Value.getLValueBase().dyn_cast<const Expr*>()) {
|
||||
if (isa<CXXUuidofExpr>(E)) {
|
||||
Converted = TemplateArgument(ArgResult.get());
|
||||
Converted = TemplateArgument(ArgResult.get()->IgnoreImpCasts());
|
||||
break;
|
||||
}
|
||||
Diag(Arg->getBeginLoc(), diag::err_template_arg_not_decl_ref)
|
||||
|
@ -1442,7 +1442,12 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
|
||||
else
|
||||
Result = Context.Int128Ty;
|
||||
break;
|
||||
case DeclSpec::TST_float16: Result = Context.Float16Ty; break;
|
||||
case DeclSpec::TST_float16:
|
||||
if (!S.Context.getTargetInfo().hasFloat16Type())
|
||||
S.Diag(DS.getTypeSpecTypeLoc(), diag::err_type_unsupported)
|
||||
<< "_Float16";
|
||||
Result = Context.Float16Ty;
|
||||
break;
|
||||
case DeclSpec::TST_half: Result = Context.HalfTy; break;
|
||||
case DeclSpec::TST_float: Result = Context.FloatTy; break;
|
||||
case DeclSpec::TST_double:
|
||||
|
@ -108,5 +108,27 @@ ArgumentsAdjuster combineAdjusters(ArgumentsAdjuster First,
|
||||
};
|
||||
}
|
||||
|
||||
ArgumentsAdjuster getStripPluginsAdjuster() {
|
||||
return [](const CommandLineArguments &Args, StringRef /*unused*/) {
|
||||
CommandLineArguments AdjustedArgs;
|
||||
for (size_t I = 0, E = Args.size(); I != E; I++) {
|
||||
// According to https://clang.llvm.org/docs/ClangPlugins.html
|
||||
// plugin arguments are in the form:
|
||||
// -Xclang {-load, -plugin, -plugin-arg-<plugin-name>, -add-plugin}
|
||||
// -Xclang <arbitrary-argument>
|
||||
if (I + 4 < E && Args[I] == "-Xclang" &&
|
||||
(Args[I + 1] == "-load" || Args[I + 1] == "-plugin" ||
|
||||
llvm::StringRef(Args[I + 1]).startswith("-plugin-arg-") ||
|
||||
Args[I + 1] == "-add-plugin") &&
|
||||
Args[I + 2] == "-Xclang") {
|
||||
I += 3;
|
||||
continue;
|
||||
}
|
||||
AdjustedArgs.push_back(Args[I]);
|
||||
}
|
||||
return AdjustedArgs;
|
||||
};
|
||||
}
|
||||
|
||||
} // end namespace tooling
|
||||
} // end namespace clang
|
||||
|
@ -669,18 +669,38 @@ const uint8_t ArmThunk[] = {
|
||||
0xe7, 0x44, // L1: add pc, ip
|
||||
};
|
||||
|
||||
size_t RangeExtensionThunk::getSize() const {
|
||||
size_t RangeExtensionThunkARM::getSize() const {
|
||||
assert(Config->Machine == ARMNT);
|
||||
return sizeof(ArmThunk);
|
||||
}
|
||||
|
||||
void RangeExtensionThunk::writeTo(uint8_t *Buf) const {
|
||||
void RangeExtensionThunkARM::writeTo(uint8_t *Buf) const {
|
||||
assert(Config->Machine == ARMNT);
|
||||
uint64_t Offset = Target->getRVA() - RVA - 12;
|
||||
memcpy(Buf + OutputSectionOff, ArmThunk, sizeof(ArmThunk));
|
||||
applyMOV32T(Buf + OutputSectionOff, uint32_t(Offset));
|
||||
}
|
||||
|
||||
// A position independent ARM64 adrp+add thunk, with a maximum range of
|
||||
// +/- 4 GB, which is enough for any PE-COFF.
|
||||
const uint8_t Arm64Thunk[] = {
|
||||
0x10, 0x00, 0x00, 0x90, // adrp x16, Dest
|
||||
0x10, 0x02, 0x00, 0x91, // add x16, x16, :lo12:Dest
|
||||
0x00, 0x02, 0x1f, 0xd6, // br x16
|
||||
};
|
||||
|
||||
size_t RangeExtensionThunkARM64::getSize() const {
|
||||
assert(Config->Machine == ARM64);
|
||||
return sizeof(Arm64Thunk);
|
||||
}
|
||||
|
||||
void RangeExtensionThunkARM64::writeTo(uint8_t *Buf) const {
|
||||
assert(Config->Machine == ARM64);
|
||||
memcpy(Buf + OutputSectionOff, Arm64Thunk, sizeof(Arm64Thunk));
|
||||
applyArm64Addr(Buf + OutputSectionOff + 0, Target->getRVA(), RVA, 12);
|
||||
applyArm64Imm(Buf + OutputSectionOff + 4, Target->getRVA() & 0xfff, 0);
|
||||
}
|
||||
|
||||
void LocalImportChunk::getBaserels(std::vector<Baserel> *Res) {
|
||||
Res->emplace_back(getRVA());
|
||||
}
|
||||
|
@ -355,9 +355,18 @@ class ImportThunkChunkARM64 : public Chunk {
|
||||
Defined *ImpSymbol;
|
||||
};
|
||||
|
||||
class RangeExtensionThunk : public Chunk {
|
||||
class RangeExtensionThunkARM : public Chunk {
|
||||
public:
|
||||
explicit RangeExtensionThunk(Defined *T) : Target(T) {}
|
||||
explicit RangeExtensionThunkARM(Defined *T) : Target(T) {}
|
||||
size_t getSize() const override;
|
||||
void writeTo(uint8_t *Buf) const override;
|
||||
|
||||
Defined *Target;
|
||||
};
|
||||
|
||||
class RangeExtensionThunkARM64 : public Chunk {
|
||||
public:
|
||||
explicit RangeExtensionThunkARM64(Defined *T) : Target(T) {}
|
||||
size_t getSize() const override;
|
||||
void writeTo(uint8_t *Buf) const override;
|
||||
|
||||
|
@ -47,6 +47,7 @@ class HintNameChunk : public Chunk {
|
||||
}
|
||||
|
||||
void writeTo(uint8_t *Buf) const override {
|
||||
memset(Buf + OutputSectionOff, 0, getSize());
|
||||
write16le(Buf + OutputSectionOff, Hint);
|
||||
memcpy(Buf + OutputSectionOff + 2, Name.data(), Name.size());
|
||||
}
|
||||
@ -63,7 +64,10 @@ class LookupChunk : public Chunk {
|
||||
size_t getSize() const override { return Config->Wordsize; }
|
||||
|
||||
void writeTo(uint8_t *Buf) const override {
|
||||
write32le(Buf + OutputSectionOff, HintName->getRVA());
|
||||
if (Config->is64())
|
||||
write64le(Buf + OutputSectionOff, HintName->getRVA());
|
||||
else
|
||||
write32le(Buf + OutputSectionOff, HintName->getRVA());
|
||||
}
|
||||
|
||||
Chunk *HintName;
|
||||
@ -99,6 +103,8 @@ class ImportDirectoryChunk : public Chunk {
|
||||
size_t getSize() const override { return sizeof(ImportDirectoryTableEntry); }
|
||||
|
||||
void writeTo(uint8_t *Buf) const override {
|
||||
memset(Buf + OutputSectionOff, 0, getSize());
|
||||
|
||||
auto *E = (coff_import_directory_table_entry *)(Buf + OutputSectionOff);
|
||||
E->ImportLookupTableRVA = LookupTab->getRVA();
|
||||
E->NameRVA = DLLName->getRVA();
|
||||
@ -118,6 +124,10 @@ class NullChunk : public Chunk {
|
||||
bool hasData() const override { return false; }
|
||||
size_t getSize() const override { return Size; }
|
||||
|
||||
void writeTo(uint8_t *Buf) const override {
|
||||
memset(Buf + OutputSectionOff, 0, Size);
|
||||
}
|
||||
|
||||
private:
|
||||
size_t Size;
|
||||
};
|
||||
@ -160,6 +170,8 @@ class DelayDirectoryChunk : public Chunk {
|
||||
}
|
||||
|
||||
void writeTo(uint8_t *Buf) const override {
|
||||
memset(Buf + OutputSectionOff, 0, getSize());
|
||||
|
||||
auto *E = (delay_import_directory_table_entry *)(Buf + OutputSectionOff);
|
||||
E->Attributes = 1;
|
||||
E->Name = DLLName->getRVA();
|
||||
@ -392,6 +404,8 @@ class ExportDirectoryChunk : public Chunk {
|
||||
}
|
||||
|
||||
void writeTo(uint8_t *Buf) const override {
|
||||
memset(Buf + OutputSectionOff, 0, getSize());
|
||||
|
||||
auto *E = (export_directory_table_entry *)(Buf + OutputSectionOff);
|
||||
E->NameRVA = DLLName->getRVA();
|
||||
E->OrdinalBase = 0;
|
||||
|
@ -263,19 +263,21 @@ void ICF::run(ArrayRef<Chunk *> Vec) {
|
||||
|
||||
// Initially, we use hash values to partition sections.
|
||||
parallelForEach(Chunks, [&](SectionChunk *SC) {
|
||||
SC->Class[1] = xxHash64(SC->getContents());
|
||||
SC->Class[0] = xxHash64(SC->getContents());
|
||||
});
|
||||
|
||||
// Combine the hashes of the sections referenced by each section into its
|
||||
// hash.
|
||||
parallelForEach(Chunks, [&](SectionChunk *SC) {
|
||||
uint32_t Hash = SC->Class[1];
|
||||
for (Symbol *B : SC->symbols())
|
||||
if (auto *Sym = dyn_cast_or_null<DefinedRegular>(B))
|
||||
Hash ^= Sym->getChunk()->Class[1];
|
||||
// Set MSB to 1 to avoid collisions with non-hash classs.
|
||||
SC->Class[0] = Hash | (1U << 31);
|
||||
});
|
||||
for (unsigned Cnt = 0; Cnt != 2; ++Cnt) {
|
||||
parallelForEach(Chunks, [&](SectionChunk *SC) {
|
||||
uint32_t Hash = SC->Class[Cnt % 2];
|
||||
for (Symbol *B : SC->symbols())
|
||||
if (auto *Sym = dyn_cast_or_null<DefinedRegular>(B))
|
||||
Hash += Sym->getChunk()->Class[Cnt % 2];
|
||||
// Set MSB to 1 to avoid collisions with non-hash classs.
|
||||
SC->Class[(Cnt + 1) % 2] = Hash | (1U << 31);
|
||||
});
|
||||
}
|
||||
|
||||
// From now on, sections in Chunks are ordered so that sections in
|
||||
// the same group are consecutive in the vector.
|
||||
|
@ -306,16 +306,31 @@ void OutputSection::writeHeaderTo(uint8_t *Buf) {
|
||||
// Check whether the target address S is in range from a relocation
|
||||
// of type RelType at address P.
|
||||
static bool isInRange(uint16_t RelType, uint64_t S, uint64_t P, int Margin) {
|
||||
assert(Config->Machine == ARMNT);
|
||||
int64_t Diff = AbsoluteDifference(S, P + 4) + Margin;
|
||||
switch (RelType) {
|
||||
case IMAGE_REL_ARM_BRANCH20T:
|
||||
return isInt<21>(Diff);
|
||||
case IMAGE_REL_ARM_BRANCH24T:
|
||||
case IMAGE_REL_ARM_BLX23T:
|
||||
return isInt<25>(Diff);
|
||||
default:
|
||||
return true;
|
||||
if (Config->Machine == ARMNT) {
|
||||
int64_t Diff = AbsoluteDifference(S, P + 4) + Margin;
|
||||
switch (RelType) {
|
||||
case IMAGE_REL_ARM_BRANCH20T:
|
||||
return isInt<21>(Diff);
|
||||
case IMAGE_REL_ARM_BRANCH24T:
|
||||
case IMAGE_REL_ARM_BLX23T:
|
||||
return isInt<25>(Diff);
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
} else if (Config->Machine == ARM64) {
|
||||
int64_t Diff = AbsoluteDifference(S, P) + Margin;
|
||||
switch (RelType) {
|
||||
case IMAGE_REL_ARM64_BRANCH26:
|
||||
return isInt<28>(Diff);
|
||||
case IMAGE_REL_ARM64_BRANCH19:
|
||||
return isInt<21>(Diff);
|
||||
case IMAGE_REL_ARM64_BRANCH14:
|
||||
return isInt<16>(Diff);
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
llvm_unreachable("Unexpected architecture");
|
||||
}
|
||||
}
|
||||
|
||||
@ -327,7 +342,17 @@ getThunk(DenseMap<uint64_t, Defined *> &LastThunks, Defined *Target, uint64_t P,
|
||||
Defined *&LastThunk = LastThunks[Target->getRVA()];
|
||||
if (LastThunk && isInRange(Type, LastThunk->getRVA(), P, Margin))
|
||||
return {LastThunk, false};
|
||||
RangeExtensionThunk *C = make<RangeExtensionThunk>(Target);
|
||||
Chunk *C;
|
||||
switch (Config->Machine) {
|
||||
case ARMNT:
|
||||
C = make<RangeExtensionThunkARM>(Target);
|
||||
break;
|
||||
case ARM64:
|
||||
C = make<RangeExtensionThunkARM64>(Target);
|
||||
break;
|
||||
default:
|
||||
llvm_unreachable("Unexpected architecture");
|
||||
}
|
||||
Defined *D = make<DefinedSynthetic>("", C);
|
||||
LastThunk = D;
|
||||
return {D, true};
|
||||
@ -344,14 +369,14 @@ getThunk(DenseMap<uint64_t, Defined *> &LastThunks, Defined *Target, uint64_t P,
|
||||
// After adding thunks, we verify that all relocations are in range (with
|
||||
// no extra margin requirements). If this failed, we restart (throwing away
|
||||
// the previously created thunks) and retry with a wider margin.
|
||||
static bool createThunks(std::vector<Chunk *> &Chunks, int Margin) {
|
||||
static bool createThunks(OutputSection *OS, int Margin) {
|
||||
bool AddressesChanged = false;
|
||||
DenseMap<uint64_t, Defined *> LastThunks;
|
||||
size_t ThunksSize = 0;
|
||||
// Recheck Chunks.size() each iteration, since we can insert more
|
||||
// elements into it.
|
||||
for (size_t I = 0; I != Chunks.size(); ++I) {
|
||||
SectionChunk *SC = dyn_cast_or_null<SectionChunk>(Chunks[I]);
|
||||
for (size_t I = 0; I != OS->Chunks.size(); ++I) {
|
||||
SectionChunk *SC = dyn_cast_or_null<SectionChunk>(OS->Chunks[I]);
|
||||
if (!SC)
|
||||
continue;
|
||||
size_t ThunkInsertionSpot = I + 1;
|
||||
@ -388,7 +413,8 @@ static bool createThunks(std::vector<Chunk *> &Chunks, int Margin) {
|
||||
Chunk *ThunkChunk = Thunk->getChunk();
|
||||
ThunkChunk->setRVA(
|
||||
ThunkInsertionRVA); // Estimate of where it will be located.
|
||||
Chunks.insert(Chunks.begin() + ThunkInsertionSpot, ThunkChunk);
|
||||
ThunkChunk->setOutputSection(OS);
|
||||
OS->Chunks.insert(OS->Chunks.begin() + ThunkInsertionSpot, ThunkChunk);
|
||||
ThunkInsertionSpot++;
|
||||
ThunksSize += ThunkChunk->getSize();
|
||||
ThunkInsertionRVA += ThunkChunk->getSize();
|
||||
@ -428,7 +454,7 @@ static bool verifyRanges(const std::vector<Chunk *> Chunks) {
|
||||
// Assign addresses and add thunks if necessary.
|
||||
void Writer::finalizeAddresses() {
|
||||
assignAddresses();
|
||||
if (Config->Machine != ARMNT)
|
||||
if (Config->Machine != ARMNT && Config->Machine != ARM64)
|
||||
return;
|
||||
|
||||
size_t OrigNumChunks = 0;
|
||||
@ -477,7 +503,7 @@ void Writer::finalizeAddresses() {
|
||||
// to avoid things going out of range due to the added thunks.
|
||||
bool AddressesChanged = false;
|
||||
for (OutputSection *Sec : OutputSections)
|
||||
AddressesChanged |= createThunks(Sec->Chunks, Margin);
|
||||
AddressesChanged |= createThunks(Sec, Margin);
|
||||
// If the verification above thought we needed thunks, we should have
|
||||
// added some.
|
||||
assert(AddressesChanged);
|
||||
|
@ -426,16 +426,17 @@ void ICF<ELFT>::forEachClass(llvm::function_ref<void(size_t, size_t)> Fn) {
|
||||
// Combine the hashes of the sections referenced by the given section into its
|
||||
// hash.
|
||||
template <class ELFT, class RelTy>
|
||||
static void combineRelocHashes(InputSection *IS, ArrayRef<RelTy> Rels) {
|
||||
uint32_t Hash = IS->Class[1];
|
||||
static void combineRelocHashes(unsigned Cnt, InputSection *IS,
|
||||
ArrayRef<RelTy> Rels) {
|
||||
uint32_t Hash = IS->Class[Cnt % 2];
|
||||
for (RelTy Rel : Rels) {
|
||||
Symbol &S = IS->template getFile<ELFT>()->getRelocTargetSym(Rel);
|
||||
if (auto *D = dyn_cast<Defined>(&S))
|
||||
if (auto *RelSec = dyn_cast_or_null<InputSection>(D->Section))
|
||||
Hash ^= RelSec->Class[1];
|
||||
Hash += RelSec->Class[Cnt % 2];
|
||||
}
|
||||
// Set MSB to 1 to avoid collisions with non-hash IDs.
|
||||
IS->Class[0] = Hash | (1U << 31);
|
||||
IS->Class[(Cnt + 1) % 2] = Hash | (1U << 31);
|
||||
}
|
||||
|
||||
static void print(const Twine &S) {
|
||||
@ -453,15 +454,17 @@ template <class ELFT> void ICF<ELFT>::run() {
|
||||
|
||||
// Initially, we use hash values to partition sections.
|
||||
parallelForEach(Sections, [&](InputSection *S) {
|
||||
S->Class[1] = xxHash64(S->data());
|
||||
S->Class[0] = xxHash64(S->data());
|
||||
});
|
||||
|
||||
parallelForEach(Sections, [&](InputSection *S) {
|
||||
if (S->AreRelocsRela)
|
||||
combineRelocHashes<ELFT>(S, S->template relas<ELFT>());
|
||||
else
|
||||
combineRelocHashes<ELFT>(S, S->template rels<ELFT>());
|
||||
});
|
||||
for (unsigned Cnt = 0; Cnt != 2; ++Cnt) {
|
||||
parallelForEach(Sections, [&](InputSection *S) {
|
||||
if (S->AreRelocsRela)
|
||||
combineRelocHashes<ELFT>(Cnt, S, S->template relas<ELFT>());
|
||||
else
|
||||
combineRelocHashes<ELFT>(Cnt, S, S->template rels<ELFT>());
|
||||
});
|
||||
}
|
||||
|
||||
// From now on, sections in Sections vector are ordered so that sections
|
||||
// in the same equivalence class are consecutive in the vector.
|
||||
|
@ -320,17 +320,6 @@ StringRef ObjFile<ELFT>::getShtGroupSignature(ArrayRef<Elf_Shdr> Sections,
|
||||
return Signature;
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
ArrayRef<typename ObjFile<ELFT>::Elf_Word>
|
||||
ObjFile<ELFT>::getShtGroupEntries(const Elf_Shdr &Sec) {
|
||||
const ELFFile<ELFT> &Obj = this->getObj();
|
||||
ArrayRef<Elf_Word> Entries =
|
||||
CHECK(Obj.template getSectionContentsAsArray<Elf_Word>(&Sec), this);
|
||||
if (Entries.empty() || Entries[0] != GRP_COMDAT)
|
||||
fatal(toString(this) + ": unsupported SHT_GROUP format");
|
||||
return Entries.slice(1);
|
||||
}
|
||||
|
||||
template <class ELFT> bool ObjFile<ELFT>::shouldMerge(const Elf_Shdr &Sec) {
|
||||
// On a regular link we don't merge sections if -O0 (default is -O1). This
|
||||
// sometimes makes the linker significantly faster, although the output will
|
||||
@ -440,26 +429,34 @@ void ObjFile<ELFT>::initializeSections(
|
||||
case SHT_GROUP: {
|
||||
// De-duplicate section groups by their signatures.
|
||||
StringRef Signature = getShtGroupSignature(ObjSections, Sec);
|
||||
bool IsNew = ComdatGroups.insert(CachedHashStringRef(Signature)).second;
|
||||
this->Sections[I] = &InputSection::Discarded;
|
||||
|
||||
// We only support GRP_COMDAT type of group. Get the all entries of the
|
||||
// section here to let getShtGroupEntries to check the type early for us.
|
||||
ArrayRef<Elf_Word> Entries = getShtGroupEntries(Sec);
|
||||
|
||||
// If it is a new section group, we want to keep group members.
|
||||
// Group leader sections, which contain indices of group members, are
|
||||
// discarded because they are useless beyond this point. The only
|
||||
// exception is the -r option because in order to produce re-linkable
|
||||
// object files, we want to pass through basically everything.
|
||||
ArrayRef<Elf_Word> Entries =
|
||||
CHECK(Obj.template getSectionContentsAsArray<Elf_Word>(&Sec), this);
|
||||
if (Entries.empty())
|
||||
fatal(toString(this) + ": empty SHT_GROUP");
|
||||
|
||||
// The first word of a SHT_GROUP section contains flags. Currently,
|
||||
// the standard defines only "GRP_COMDAT" flag for the COMDAT group.
|
||||
// An group with the empty flag doesn't define anything; such sections
|
||||
// are just skipped.
|
||||
if (Entries[0] == 0)
|
||||
continue;
|
||||
|
||||
if (Entries[0] != GRP_COMDAT)
|
||||
fatal(toString(this) + ": unsupported SHT_GROUP format");
|
||||
|
||||
bool IsNew = ComdatGroups.insert(CachedHashStringRef(Signature)).second;
|
||||
if (IsNew) {
|
||||
if (Config->Relocatable)
|
||||
this->Sections[I] = createInputSection(Sec);
|
||||
continue;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
// Otherwise, discard group members.
|
||||
for (uint32_t SecIndex : Entries) {
|
||||
for (uint32_t SecIndex : Entries.slice(1)) {
|
||||
if (SecIndex >= Size)
|
||||
fatal(toString(this) +
|
||||
": invalid section index in group: " + Twine(SecIndex));
|
||||
@ -739,7 +736,8 @@ InputSectionBase *ObjFile<ELFT>::createInputSection(const Elf_Shdr &Sec) {
|
||||
// sections. Drop those sections to avoid duplicate symbol errors.
|
||||
// FIXME: This is glibc PR20543, we should remove this hack once that has been
|
||||
// fixed for a while.
|
||||
if (Name.startswith(".gnu.linkonce."))
|
||||
if (Name == ".gnu.linkonce.t.__x86.get_pc_thunk.bx" ||
|
||||
Name == ".gnu.linkonce.t.__i686.get_pc_thunk.bx")
|
||||
return &InputSection::Discarded;
|
||||
|
||||
// If we are creating a new .build-id section, strip existing .build-id
|
||||
|
@ -175,7 +175,6 @@ template <class ELFT> class ObjFile : public ELFFileBase<ELFT> {
|
||||
|
||||
StringRef getShtGroupSignature(ArrayRef<Elf_Shdr> Sections,
|
||||
const Elf_Shdr &Sec);
|
||||
ArrayRef<Elf_Word> getShtGroupEntries(const Elf_Shdr &Sec);
|
||||
|
||||
public:
|
||||
static bool classof(const InputFile *F) { return F->kind() == Base::ObjKind; }
|
||||
|
@ -1513,8 +1513,10 @@ void RelocationBaseSection::finalizeContents() {
|
||||
else
|
||||
getParent()->Link = 0;
|
||||
|
||||
if (In.RelaIplt == this || In.RelaPlt == this)
|
||||
if (In.RelaPlt == this)
|
||||
getParent()->Info = In.GotPlt->getParent()->SectionIndex;
|
||||
if (In.RelaIplt == this)
|
||||
getParent()->Info = In.IgotPlt->getParent()->SectionIndex;
|
||||
}
|
||||
|
||||
RelrBaseSection::RelrBaseSection()
|
||||
|
@ -40,6 +40,9 @@ ELF Improvements
|
||||
|
||||
* The following flags have been added: ``-z interpose``, ``-z global``
|
||||
|
||||
* lld now uses the ``sigrie`` instruction as a trap instruction for
|
||||
MIPS targets.
|
||||
|
||||
COFF Improvements
|
||||
-----------------
|
||||
|
||||
@ -66,6 +69,13 @@ MinGW Improvements
|
||||
linked in a different order than with GNU ld, inserting a DWARF exception
|
||||
table terminator too early.)
|
||||
|
||||
* lld now supports COFF embedded directives for linking to nondefault
|
||||
libraries, just like for the normal COFF target.
|
||||
|
||||
* Actually generate a codeview build id signature, even if not creating a PDB.
|
||||
Previously, the ``--build-id`` option did not actually generate a build id
|
||||
unless ``--pdb`` was specified.
|
||||
|
||||
MachO Improvements
|
||||
------------------
|
||||
|
||||
|
@ -8,4 +8,4 @@
|
||||
|
||||
#define CLANG_VENDOR "FreeBSD "
|
||||
|
||||
#define SVN_REVISION "351543"
|
||||
#define SVN_REVISION "353167"
|
||||
|
@ -7,4 +7,4 @@
|
||||
|
||||
#define LLD_REPOSITORY_STRING "FreeBSD"
|
||||
// <Upstream revision at import>-<Local identifier in __FreeBSD_version style>
|
||||
#define LLD_REVISION_STRING "351543-1300002"
|
||||
#define LLD_REVISION_STRING "353167-1300002"
|
||||
|
@ -1,2 +1,2 @@
|
||||
/* $FreeBSD$ */
|
||||
#define LLVM_REVISION "svn-r351543"
|
||||
#define LLVM_REVISION "svn-r353167"
|
||||
|
Loading…
Reference in New Issue
Block a user