mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2026-04-20 16:17:38 +00:00
XCore handling of thread local lowering
Fix XCoreLowerThreadLocal trying to initialise globals which have no initializer. Add handling of const expressions containing thread local variables. These need to be replaced with instructions, as the thread ID is used to access the thread local variable. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@190300 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
@@ -22,6 +22,8 @@
|
||||
#include "llvm/IR/Module.h"
|
||||
#include "llvm/Pass.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/NoFolder.h"
|
||||
#include "llvm/Support/ValueHandle.h"
|
||||
|
||||
#define DEBUG_TYPE "xcore-lower-thread-local"
|
||||
|
||||
@@ -71,13 +73,94 @@ createLoweredInitializer(ArrayType *NewType, Constant *OriginalInitializer) {
|
||||
return ConstantArray::get(NewType, Elements);
|
||||
}
|
||||
|
||||
static bool hasNonInstructionUse(GlobalVariable *GV) {
|
||||
for (Value::use_iterator UI = GV->use_begin(), E = GV->use_end(); UI != E;
|
||||
++UI)
|
||||
if (!isa<Instruction>(*UI))
|
||||
return true;
|
||||
static Instruction *
|
||||
createReplacementInstr(ConstantExpr *CE, Instruction *Instr) {
|
||||
IRBuilder<true,NoFolder> Builder(Instr);
|
||||
unsigned OpCode = CE->getOpcode();
|
||||
switch (OpCode) {
|
||||
case Instruction::GetElementPtr: {
|
||||
SmallVector<Value *,4> CEOpVec(CE->op_begin(), CE->op_end());
|
||||
ArrayRef<Value *> CEOps(CEOpVec);
|
||||
return dyn_cast<Instruction>(Builder.CreateInBoundsGEP(CEOps[0],
|
||||
CEOps.slice(1)));
|
||||
}
|
||||
case Instruction::Add:
|
||||
case Instruction::Sub:
|
||||
case Instruction::Mul:
|
||||
case Instruction::UDiv:
|
||||
case Instruction::SDiv:
|
||||
case Instruction::FDiv:
|
||||
case Instruction::URem:
|
||||
case Instruction::SRem:
|
||||
case Instruction::FRem:
|
||||
case Instruction::Shl:
|
||||
case Instruction::LShr:
|
||||
case Instruction::AShr:
|
||||
case Instruction::And:
|
||||
case Instruction::Or:
|
||||
case Instruction::Xor:
|
||||
return dyn_cast<Instruction>(
|
||||
Builder.CreateBinOp((Instruction::BinaryOps)OpCode,
|
||||
CE->getOperand(0), CE->getOperand(1),
|
||||
CE->getName()));
|
||||
case Instruction::Trunc:
|
||||
case Instruction::ZExt:
|
||||
case Instruction::SExt:
|
||||
case Instruction::FPToUI:
|
||||
case Instruction::FPToSI:
|
||||
case Instruction::UIToFP:
|
||||
case Instruction::SIToFP:
|
||||
case Instruction::FPTrunc:
|
||||
case Instruction::FPExt:
|
||||
case Instruction::PtrToInt:
|
||||
case Instruction::IntToPtr:
|
||||
case Instruction::BitCast:
|
||||
return dyn_cast<Instruction>(
|
||||
Builder.CreateCast((Instruction::CastOps)OpCode,
|
||||
CE->getOperand(0), CE->getType(),
|
||||
CE->getName()));
|
||||
default:
|
||||
assert(0 && "Unhandled constant expression!\n");
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
static bool replaceConstantExprOp(ConstantExpr *CE) {
|
||||
do {
|
||||
SmallVector<WeakVH,8> WUsers;
|
||||
for (Value::use_iterator I = CE->use_begin(), E = CE->use_end();
|
||||
I != E; ++I)
|
||||
WUsers.push_back(WeakVH(*I));
|
||||
while (!WUsers.empty())
|
||||
if (WeakVH WU = WUsers.pop_back_val()) {
|
||||
if (Instruction *Instr = dyn_cast<Instruction>(WU)) {
|
||||
Instruction *NewInst = createReplacementInstr(CE, Instr);
|
||||
assert(NewInst && "Must build an instruction\n");
|
||||
// If NewInst uses a CE being handled in an earlier recursion the
|
||||
// earlier recursion's do-while-hasNUsesOrMore(1) will run again.
|
||||
Instr->replaceUsesOfWith(CE, NewInst);
|
||||
} else {
|
||||
ConstantExpr *CExpr = dyn_cast<ConstantExpr>(WU);
|
||||
if (!CExpr || !replaceConstantExprOp(CExpr))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} while (CE->hasNUsesOrMore(1)); // Does a recursion's NewInst use CE?
|
||||
CE->destroyConstant();
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool rewriteNonInstructionUses(GlobalVariable *GV) {
|
||||
SmallVector<WeakVH,8> WUsers;
|
||||
for (Value::use_iterator I = GV->use_begin(), E = GV->use_end(); I != E; ++I)
|
||||
if (!isa<Instruction>(*I))
|
||||
WUsers.push_back(WeakVH(*I));
|
||||
while (!WUsers.empty())
|
||||
if (WeakVH WU = WUsers.pop_back_val()) {
|
||||
ConstantExpr *CE = dyn_cast<ConstantExpr>(WU);
|
||||
if (!CE || !replaceConstantExprOp(CE))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool isZeroLengthArray(Type *Ty) {
|
||||
@@ -92,14 +175,16 @@ bool XCoreLowerThreadLocal::lowerGlobal(GlobalVariable *GV) {
|
||||
return false;
|
||||
|
||||
// Skip globals that we can't lower and leave it for the backend to error.
|
||||
if (hasNonInstructionUse(GV) ||
|
||||
if (!rewriteNonInstructionUses(GV) ||
|
||||
!GV->getType()->isSized() || isZeroLengthArray(GV->getType()))
|
||||
return false;
|
||||
|
||||
// Create replacement global.
|
||||
ArrayType *NewType = createLoweredType(GV->getType()->getElementType());
|
||||
Constant *NewInitializer = createLoweredInitializer(NewType,
|
||||
GV->getInitializer());
|
||||
Constant *NewInitializer = 0;
|
||||
if (GV->hasInitializer())
|
||||
NewInitializer = createLoweredInitializer(NewType,
|
||||
GV->getInitializer());
|
||||
GlobalVariable *NewGV =
|
||||
new GlobalVariable(*M, NewType, GV->isConstant(), GV->getLinkage(),
|
||||
NewInitializer, "", 0, GlobalVariable::NotThreadLocal,
|
||||
|
||||
Reference in New Issue
Block a user