mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2025-02-01 05:01:59 +01:00
[WebAssembly] Fast-isel support for calls, arguments, and selects.
llvm-svn: 269273
This commit is contained in:
parent
ff8397dabb
commit
fffd2940a1
@ -12,10 +12,13 @@
|
||||
/// class. Some of the target-specific code is generated by tablegen in the file
|
||||
/// WebAssemblyGenFastISel.inc, which is #included here.
|
||||
///
|
||||
/// TODO: kill flags
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "WebAssembly.h"
|
||||
#include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
|
||||
#include "WebAssemblyMachineFunctionInfo.h"
|
||||
#include "WebAssemblySubtarget.h"
|
||||
#include "WebAssemblyTargetMachine.h"
|
||||
#include "llvm/Analysis/BranchProbabilityInfo.h"
|
||||
@ -104,10 +107,12 @@ private:
|
||||
case MVT::i1:
|
||||
case MVT::i8:
|
||||
case MVT::i16:
|
||||
case MVT::i32:
|
||||
return MVT::i32;
|
||||
case MVT::i32:
|
||||
case MVT::i64:
|
||||
return MVT::i64;
|
||||
case MVT::f32:
|
||||
case MVT::f64:
|
||||
return VT;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -118,7 +123,7 @@ private:
|
||||
void addLoadStoreOperands(const Address &Addr, const MachineInstrBuilder &MIB,
|
||||
MachineMemOperand *MMO);
|
||||
unsigned maskI1Value(unsigned Reg, const Value *V);
|
||||
unsigned getRegForI1Value(const Value *V);
|
||||
unsigned getRegForI1Value(const Value *V, bool &Not);
|
||||
unsigned zeroExtendToI32(unsigned Reg, const Value *V,
|
||||
MVT::SimpleValueType From);
|
||||
unsigned signExtendToI32(unsigned Reg, const Value *V,
|
||||
@ -133,12 +138,17 @@ private:
|
||||
unsigned getRegForSignedValue(const Value *V);
|
||||
unsigned getRegForPromotedValue(const Value *V, bool IsSigned);
|
||||
unsigned notValue(unsigned Reg);
|
||||
unsigned copyValue(unsigned Reg);
|
||||
|
||||
// Backend specific FastISel code.
|
||||
unsigned fastMaterializeAlloca(const AllocaInst *AI) override;
|
||||
unsigned fastMaterializeConstant(const Constant *C) override;
|
||||
bool fastLowerArguments() override;
|
||||
|
||||
// Selection routines.
|
||||
bool selectCall(const Instruction *I);
|
||||
bool selectSelect(const Instruction *I);
|
||||
bool selectTrunc(const Instruction *I);
|
||||
bool selectZExt(const Instruction *I);
|
||||
bool selectSExt(const Instruction *I);
|
||||
bool selectICmp(const Instruction *I);
|
||||
@ -221,7 +231,7 @@ bool WebAssemblyFastISel::computeAddress(const Value *Obj, Address &Addr) {
|
||||
uint64_t TmpOffset = Addr.getOffset();
|
||||
// Iterate through the GEP folding the constants into offsets where
|
||||
// we can.
|
||||
for (gep_type_iterator GTI = gep_type_begin(U), E = gep_type_end(U);
|
||||
for (gep_type_iterator GTI = gep_type_begin(U), E = gep_type_end(U);
|
||||
GTI != E; ++GTI) {
|
||||
const Value *Op = GTI.getOperand();
|
||||
if (StructType *STy = dyn_cast<StructType>(*GTI)) {
|
||||
@ -236,6 +246,11 @@ bool WebAssemblyFastISel::computeAddress(const Value *Obj, Address &Addr) {
|
||||
TmpOffset += CI->getSExtValue() * S;
|
||||
break;
|
||||
}
|
||||
if (S == 1 && Addr.isRegBase() && Addr.getReg() == 0) {
|
||||
// An unscaled add of a register. Set it as the new base.
|
||||
Addr.setReg(getRegForValue(Op));
|
||||
break;
|
||||
}
|
||||
if (canFoldAddIntoGEP(U, Op)) {
|
||||
// A compatible add with a constant operand. Fold the constant.
|
||||
ConstantInt *CI =
|
||||
@ -347,7 +362,20 @@ unsigned WebAssemblyFastISel::maskI1Value(unsigned Reg, const Value *V) {
|
||||
return zeroExtendToI32(Reg, V, MVT::i1);
|
||||
}
|
||||
|
||||
unsigned WebAssemblyFastISel::getRegForI1Value(const Value *V) {
|
||||
unsigned WebAssemblyFastISel::getRegForI1Value(const Value *V, bool &Not) {
|
||||
if (const ICmpInst *ICmp = dyn_cast<ICmpInst>(V))
|
||||
if (const ConstantInt *C = dyn_cast<ConstantInt>(ICmp->getOperand(1)))
|
||||
if (ICmp->isEquality() && C->isZero() && C->getType()->isIntegerTy(32)) {
|
||||
Not = ICmp->isTrueWhenEqual();
|
||||
return getRegForValue(ICmp->getOperand(0));
|
||||
}
|
||||
|
||||
if (BinaryOperator::isNot(V)) {
|
||||
Not = true;
|
||||
return getRegForValue(BinaryOperator::getNotArgument(V));
|
||||
}
|
||||
|
||||
Not = false;
|
||||
return maskI1Value(getRegForValue(V), V);
|
||||
}
|
||||
|
||||
@ -357,11 +385,16 @@ unsigned WebAssemblyFastISel::zeroExtendToI32(unsigned Reg, const Value *V,
|
||||
case MVT::i1:
|
||||
// If the value is naturally an i1, we don't need to mask it.
|
||||
// TODO: Recursively examine selects, phis, and, or, xor, constants.
|
||||
if (From == MVT::i1 && V != nullptr && isa<CmpInst>(V))
|
||||
return Reg;
|
||||
if (From == MVT::i1 && V != nullptr) {
|
||||
if (isa<CmpInst>(V) ||
|
||||
(isa<Argument>(V) && cast<Argument>(V)->hasZExtAttr()))
|
||||
return copyValue(Reg);
|
||||
}
|
||||
case MVT::i8:
|
||||
case MVT::i16:
|
||||
break;
|
||||
case MVT::i32:
|
||||
return Reg;
|
||||
return copyValue(Reg);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
@ -388,9 +421,9 @@ unsigned WebAssemblyFastISel::signExtendToI32(unsigned Reg, const Value *V,
|
||||
case MVT::i16:
|
||||
break;
|
||||
case MVT::i32:
|
||||
return Reg;
|
||||
return copyValue(Reg);
|
||||
default:
|
||||
return false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned Imm = createResultReg(&WebAssembly::I32RegClass);
|
||||
@ -418,7 +451,7 @@ unsigned WebAssemblyFastISel::zeroExtend(unsigned Reg, const Value *V,
|
||||
MVT::SimpleValueType To) {
|
||||
if (To == MVT::i64) {
|
||||
if (From == MVT::i64)
|
||||
return Reg;
|
||||
return copyValue(Reg);
|
||||
|
||||
Reg = zeroExtendToI32(Reg, V, From);
|
||||
|
||||
@ -429,21 +462,6 @@ unsigned WebAssemblyFastISel::zeroExtend(unsigned Reg, const Value *V,
|
||||
return Result;
|
||||
}
|
||||
|
||||
switch (From) {
|
||||
case MVT::i1:
|
||||
// If the value is naturally an i1, we don't need to mask it.
|
||||
// TODO: Recursively examine selects, phis, and, or, xor, constants.
|
||||
if (From == MVT::i1 && V != nullptr && isa<CmpInst>(V))
|
||||
return Reg;
|
||||
case MVT::i8:
|
||||
case MVT::i16:
|
||||
break;
|
||||
case MVT::i32:
|
||||
return Reg;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
return zeroExtendToI32(Reg, V, From);
|
||||
}
|
||||
|
||||
@ -452,7 +470,7 @@ unsigned WebAssemblyFastISel::signExtend(unsigned Reg, const Value *V,
|
||||
MVT::SimpleValueType To) {
|
||||
if (To == MVT::i64) {
|
||||
if (From == MVT::i64)
|
||||
return Reg;
|
||||
return copyValue(Reg);
|
||||
|
||||
Reg = signExtendToI32(Reg, V, From);
|
||||
|
||||
@ -463,17 +481,6 @@ unsigned WebAssemblyFastISel::signExtend(unsigned Reg, const Value *V,
|
||||
return Result;
|
||||
}
|
||||
|
||||
switch (From) {
|
||||
case MVT::i1:
|
||||
case MVT::i8:
|
||||
case MVT::i16:
|
||||
break;
|
||||
case MVT::i32:
|
||||
return Reg;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
return signExtendToI32(Reg, V, From);
|
||||
}
|
||||
|
||||
@ -496,6 +503,8 @@ unsigned WebAssemblyFastISel::getRegForPromotedValue(const Value *V,
|
||||
}
|
||||
|
||||
unsigned WebAssemblyFastISel::notValue(unsigned Reg) {
|
||||
assert(MRI.getRegClass(Reg) == &WebAssembly::I32RegClass);
|
||||
|
||||
unsigned NotReg = createResultReg(&WebAssembly::I32RegClass);
|
||||
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
|
||||
TII.get(WebAssembly::EQZ_I32), NotReg)
|
||||
@ -503,6 +512,14 @@ unsigned WebAssemblyFastISel::notValue(unsigned Reg) {
|
||||
return NotReg;
|
||||
}
|
||||
|
||||
unsigned WebAssemblyFastISel::copyValue(unsigned Reg) {
|
||||
unsigned ResultReg = createResultReg(MRI.getRegClass(Reg));
|
||||
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
|
||||
TII.get(WebAssembly::COPY), ResultReg)
|
||||
.addReg(Reg);
|
||||
return ResultReg;
|
||||
}
|
||||
|
||||
unsigned WebAssemblyFastISel::fastMaterializeAlloca(const AllocaInst *AI) {
|
||||
DenseMap<const AllocaInst *, int>::iterator SI =
|
||||
FuncInfo.StaticAllocaMap.find(AI);
|
||||
@ -524,25 +541,259 @@ unsigned WebAssemblyFastISel::fastMaterializeAlloca(const AllocaInst *AI) {
|
||||
|
||||
unsigned WebAssemblyFastISel::fastMaterializeConstant(const Constant *C) {
|
||||
if (const GlobalValue *GV = dyn_cast<GlobalValue>(C)) {
|
||||
unsigned Reg = createResultReg(Subtarget->hasAddr64() ?
|
||||
&WebAssembly::I64RegClass :
|
||||
&WebAssembly::I32RegClass);
|
||||
unsigned ResultReg = createResultReg(Subtarget->hasAddr64() ?
|
||||
&WebAssembly::I64RegClass :
|
||||
&WebAssembly::I32RegClass);
|
||||
unsigned Opc = Subtarget->hasAddr64() ?
|
||||
WebAssembly::CONST_I64 :
|
||||
WebAssembly::CONST_I32;
|
||||
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), Reg)
|
||||
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg)
|
||||
.addGlobalAddress(GV);
|
||||
return Reg;
|
||||
return ResultReg;
|
||||
}
|
||||
|
||||
// Let target-independent code handle it.
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool WebAssemblyFastISel::fastLowerArguments() {
|
||||
if (!FuncInfo.CanLowerReturn)
|
||||
return false;
|
||||
|
||||
const Function *F = FuncInfo.Fn;
|
||||
if (F->isVarArg())
|
||||
return false;
|
||||
|
||||
unsigned i = 0;
|
||||
for (auto const &Arg : F->args()) {
|
||||
const AttributeSet &Attrs = F->getAttributes();
|
||||
if (Attrs.hasAttribute(i+1, Attribute::ByVal) ||
|
||||
Attrs.hasAttribute(i+1, Attribute::SwiftSelf) ||
|
||||
Attrs.hasAttribute(i+1, Attribute::SwiftError) ||
|
||||
Attrs.hasAttribute(i+1, Attribute::InAlloca) ||
|
||||
Attrs.hasAttribute(i+1, Attribute::Nest))
|
||||
return false;
|
||||
|
||||
Type *ArgTy = Arg.getType();
|
||||
if (ArgTy->isStructTy() || ArgTy->isArrayTy() || ArgTy->isVectorTy())
|
||||
return false;
|
||||
|
||||
unsigned Opc;
|
||||
const TargetRegisterClass *RC;
|
||||
switch (getSimpleType(ArgTy)) {
|
||||
case MVT::i1:
|
||||
case MVT::i8:
|
||||
case MVT::i16:
|
||||
case MVT::i32:
|
||||
Opc = WebAssembly::ARGUMENT_I32;
|
||||
RC = &WebAssembly::I32RegClass;
|
||||
break;
|
||||
case MVT::i64:
|
||||
Opc = WebAssembly::ARGUMENT_I64;
|
||||
RC = &WebAssembly::I64RegClass;
|
||||
break;
|
||||
case MVT::f32:
|
||||
Opc = WebAssembly::ARGUMENT_F32;
|
||||
RC = &WebAssembly::F32RegClass;
|
||||
break;
|
||||
case MVT::f64:
|
||||
Opc = WebAssembly::ARGUMENT_F64;
|
||||
RC = &WebAssembly::F64RegClass;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
unsigned ResultReg = createResultReg(RC);
|
||||
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg)
|
||||
.addImm(i);
|
||||
updateValueMap(&Arg, ResultReg);
|
||||
|
||||
++i;
|
||||
}
|
||||
|
||||
MRI.addLiveIn(WebAssembly::ARGUMENTS);
|
||||
|
||||
auto *MFI = MF->getInfo<WebAssemblyFunctionInfo>();
|
||||
for (auto const &Arg : F->args())
|
||||
MFI->addParam(getLegalType(getSimpleType(Arg.getType())));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WebAssemblyFastISel::selectCall(const Instruction *I) {
|
||||
const CallInst *Call = cast<CallInst>(I);
|
||||
|
||||
if (Call->isMustTailCall() || Call->isInlineAsm() ||
|
||||
Call->getFunctionType()->isVarArg())
|
||||
return false;
|
||||
|
||||
Function *Func = Call->getCalledFunction();
|
||||
if (Func && Func->isIntrinsic())
|
||||
return false;
|
||||
|
||||
FunctionType *FuncTy = Call->getFunctionType();
|
||||
unsigned Opc;
|
||||
bool IsDirect = Func != nullptr;
|
||||
bool IsVoid = FuncTy->getReturnType()->isVoidTy();
|
||||
unsigned ResultReg;
|
||||
if (IsVoid) {
|
||||
Opc = IsDirect ? WebAssembly::CALL_VOID : WebAssembly::CALL_INDIRECT_VOID;
|
||||
} else {
|
||||
MVT::SimpleValueType RetTy = getSimpleType(Call->getType());
|
||||
switch (RetTy) {
|
||||
case MVT::i1:
|
||||
case MVT::i8:
|
||||
case MVT::i16:
|
||||
case MVT::i32:
|
||||
Opc = IsDirect ? WebAssembly::CALL_I32 : WebAssembly::CALL_INDIRECT_I32;
|
||||
ResultReg = createResultReg(&WebAssembly::I32RegClass);
|
||||
break;
|
||||
case MVT::i64:
|
||||
Opc = IsDirect ? WebAssembly::CALL_I64 : WebAssembly::CALL_INDIRECT_I64;
|
||||
ResultReg = createResultReg(&WebAssembly::I64RegClass);
|
||||
break;
|
||||
case MVT::f32:
|
||||
Opc = IsDirect ? WebAssembly::CALL_F32 : WebAssembly::CALL_INDIRECT_F32;
|
||||
ResultReg = createResultReg(&WebAssembly::F32RegClass);
|
||||
break;
|
||||
case MVT::f64:
|
||||
Opc = IsDirect ? WebAssembly::CALL_F64 : WebAssembly::CALL_INDIRECT_F64;
|
||||
ResultReg = createResultReg(&WebAssembly::F64RegClass);
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
SmallVector<unsigned, 8> Args;
|
||||
for (unsigned i = 0, e = Call->getNumArgOperands(); i < e; ++i) {
|
||||
Value *V = Call->getArgOperand(i);
|
||||
MVT::SimpleValueType ArgTy = getSimpleType(V->getType());
|
||||
if (ArgTy == MVT::INVALID_SIMPLE_VALUE_TYPE)
|
||||
return false;
|
||||
|
||||
const AttributeSet &Attrs = Call->getAttributes();
|
||||
if (Attrs.hasAttribute(i+1, Attribute::ByVal) ||
|
||||
Attrs.hasAttribute(i+1, Attribute::SwiftSelf) ||
|
||||
Attrs.hasAttribute(i+1, Attribute::SwiftError) ||
|
||||
Attrs.hasAttribute(i+1, Attribute::InAlloca) ||
|
||||
Attrs.hasAttribute(i+1, Attribute::Nest))
|
||||
return false;
|
||||
|
||||
unsigned Reg;
|
||||
|
||||
if (Attrs.hasAttribute(i+1, Attribute::SExt))
|
||||
Reg = getRegForSignedValue(V);
|
||||
else if (Attrs.hasAttribute(i+1, Attribute::ZExt))
|
||||
Reg = getRegForUnsignedValue(V);
|
||||
else
|
||||
Reg = getRegForValue(V);
|
||||
|
||||
if (Reg == 0)
|
||||
return false;
|
||||
|
||||
Args.push_back(Reg);
|
||||
}
|
||||
|
||||
auto MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc));
|
||||
|
||||
if (!IsVoid)
|
||||
MIB.addReg(ResultReg, RegState::Define);
|
||||
|
||||
if (IsDirect)
|
||||
MIB.addGlobalAddress(Func);
|
||||
else
|
||||
MIB.addReg(getRegForValue(Call->getCalledValue()));
|
||||
|
||||
for (unsigned ArgReg : Args)
|
||||
MIB.addReg(ArgReg);
|
||||
|
||||
if (!IsVoid)
|
||||
updateValueMap(Call, ResultReg);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WebAssemblyFastISel::selectSelect(const Instruction *I) {
|
||||
const SelectInst *Select = cast<SelectInst>(I);
|
||||
|
||||
bool Not;
|
||||
unsigned CondReg = getRegForI1Value(Select->getCondition(), Not);
|
||||
if (CondReg == 0)
|
||||
return false;
|
||||
|
||||
unsigned TrueReg = getRegForValue(Select->getTrueValue());
|
||||
if (TrueReg == 0)
|
||||
return false;
|
||||
|
||||
unsigned FalseReg = getRegForValue(Select->getFalseValue());
|
||||
if (FalseReg == 0)
|
||||
return false;
|
||||
|
||||
if (Not)
|
||||
std::swap(TrueReg, FalseReg);
|
||||
|
||||
unsigned Opc;
|
||||
const TargetRegisterClass *RC;
|
||||
switch (getSimpleType(Select->getType())) {
|
||||
case MVT::i1:
|
||||
case MVT::i8:
|
||||
case MVT::i16:
|
||||
case MVT::i32:
|
||||
Opc = WebAssembly::SELECT_I32;
|
||||
RC = &WebAssembly::I32RegClass;
|
||||
break;
|
||||
case MVT::i64:
|
||||
Opc = WebAssembly::SELECT_I64;
|
||||
RC = &WebAssembly::I64RegClass;
|
||||
break;
|
||||
case MVT::f32:
|
||||
Opc = WebAssembly::SELECT_F32;
|
||||
RC = &WebAssembly::F32RegClass;
|
||||
break;
|
||||
case MVT::f64:
|
||||
Opc = WebAssembly::SELECT_F64;
|
||||
RC = &WebAssembly::F64RegClass;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned ResultReg = createResultReg(RC);
|
||||
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg)
|
||||
.addReg(TrueReg)
|
||||
.addReg(FalseReg)
|
||||
.addReg(CondReg);
|
||||
|
||||
updateValueMap(Select, ResultReg);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WebAssemblyFastISel::selectTrunc(const Instruction *I) {
|
||||
const TruncInst *Trunc = cast<TruncInst>(I);
|
||||
|
||||
unsigned Reg = getRegForValue(Trunc->getOperand(0));
|
||||
if (Reg == 0)
|
||||
return false;
|
||||
|
||||
if (Trunc->getOperand(0)->getType()->isIntegerTy(64)) {
|
||||
unsigned Result = createResultReg(&WebAssembly::I32RegClass);
|
||||
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
|
||||
TII.get(WebAssembly::I32_WRAP_I64), Result)
|
||||
.addReg(Reg);
|
||||
Reg = Result;
|
||||
}
|
||||
|
||||
updateValueMap(Trunc, Reg);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WebAssemblyFastISel::selectZExt(const Instruction *I) {
|
||||
const ZExtInst *ZExt = cast<ZExtInst>(I);
|
||||
|
||||
unsigned Reg = getRegForUnsignedValue(ZExt->getOperand(0));
|
||||
const Value *Op = ZExt->getOperand(0);
|
||||
MVT::SimpleValueType From = getSimpleType(Op->getType());
|
||||
MVT::SimpleValueType To = getLegalType(getSimpleType(ZExt->getType()));
|
||||
unsigned Reg = zeroExtend(getRegForValue(Op), Op, From, To);
|
||||
if (Reg == 0)
|
||||
return false;
|
||||
|
||||
@ -553,7 +804,10 @@ bool WebAssemblyFastISel::selectZExt(const Instruction *I) {
|
||||
bool WebAssemblyFastISel::selectSExt(const Instruction *I) {
|
||||
const SExtInst *SExt = cast<SExtInst>(I);
|
||||
|
||||
unsigned Reg = getRegForSignedValue(SExt->getOperand(0));
|
||||
const Value *Op = SExt->getOperand(0);
|
||||
MVT::SimpleValueType From = getSimpleType(Op->getType());
|
||||
MVT::SimpleValueType To = getLegalType(getSimpleType(SExt->getType()));
|
||||
unsigned Reg = signExtend(getRegForValue(Op), Op, From, To);
|
||||
if (Reg == 0)
|
||||
return false;
|
||||
|
||||
@ -694,6 +948,13 @@ bool WebAssemblyFastISel::selectBitCast(const Instruction *I) {
|
||||
EVT RetVT = TLI.getValueType(DL, I->getType());
|
||||
if (!VT.isSimple() || !RetVT.isSimple())
|
||||
return false;
|
||||
|
||||
if (VT == RetVT) {
|
||||
// No-op bitcast.
|
||||
updateValueMap(I, getRegForValue(I->getOperand(0)));
|
||||
return true;
|
||||
}
|
||||
|
||||
unsigned Reg = fastEmit_ISD_BITCAST_r(VT.getSimpleVT(), RetVT.getSimpleVT(),
|
||||
getRegForValue(I->getOperand(0)),
|
||||
I->getOperand(0)->hasOneUse());
|
||||
@ -831,14 +1092,13 @@ bool WebAssemblyFastISel::selectBr(const Instruction *I) {
|
||||
MachineBasicBlock *TBB = FuncInfo.MBBMap[Br->getSuccessor(0)];
|
||||
MachineBasicBlock *FBB = FuncInfo.MBBMap[Br->getSuccessor(1)];
|
||||
|
||||
Value *Cond = Br->getCondition();
|
||||
unsigned Opc = WebAssembly::BR_IF;
|
||||
if (BinaryOperator::isNot(Cond)) {
|
||||
Cond = BinaryOperator::getNotArgument(Cond);
|
||||
Opc = WebAssembly::BR_UNLESS;
|
||||
}
|
||||
bool Not;
|
||||
unsigned CondReg = getRegForI1Value(Br->getCondition(), Not);
|
||||
|
||||
unsigned Opc = WebAssembly::BR_IF;
|
||||
if (Not)
|
||||
Opc = WebAssembly::BR_UNLESS;
|
||||
|
||||
unsigned CondReg = getRegForI1Value(Cond);
|
||||
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc))
|
||||
.addMBB(TBB)
|
||||
.addReg(CondReg);
|
||||
@ -874,7 +1134,14 @@ bool WebAssemblyFastISel::selectRet(const Instruction *I) {
|
||||
default: return false;
|
||||
}
|
||||
|
||||
unsigned Reg = getRegForValue(RV);
|
||||
unsigned Reg;
|
||||
if (FuncInfo.Fn->getAttributes().hasAttribute(0, Attribute::SExt))
|
||||
Reg = getRegForSignedValue(RV);
|
||||
else if (FuncInfo.Fn->getAttributes().hasAttribute(0, Attribute::ZExt))
|
||||
Reg = getRegForUnsignedValue(RV);
|
||||
else
|
||||
Reg = getRegForValue(RV);
|
||||
|
||||
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc)).addReg(Reg);
|
||||
return true;
|
||||
}
|
||||
@ -887,6 +1154,12 @@ bool WebAssemblyFastISel::selectUnreachable(const Instruction *I) {
|
||||
|
||||
bool WebAssemblyFastISel::fastSelectInstruction(const Instruction *I) {
|
||||
switch (I->getOpcode()) {
|
||||
case Instruction::Call:
|
||||
if (selectCall(I))
|
||||
return true;
|
||||
break;
|
||||
case Instruction::Select: return selectSelect(I);
|
||||
case Instruction::Trunc: return selectTrunc(I);
|
||||
case Instruction::ZExt: return selectZExt(I);
|
||||
case Instruction::SExt: return selectSExt(I);
|
||||
case Instruction::ICmp: return selectICmp(I);
|
||||
|
@ -297,13 +297,14 @@ static MachineInstr *MoveAndTeeForMultiUse(
|
||||
unsigned NewReg = MRI.createVirtualRegister(RegClass);
|
||||
unsigned TeeReg = MRI.createVirtualRegister(RegClass);
|
||||
unsigned DefReg = MRI.createVirtualRegister(RegClass);
|
||||
MachineOperand &DefMO = Def->getOperand(0);
|
||||
MRI.replaceRegWith(Reg, NewReg);
|
||||
MachineInstr *Tee = BuildMI(MBB, Insert, Insert->getDebugLoc(),
|
||||
TII->get(GetTeeLocalOpcode(RegClass)), TeeReg)
|
||||
.addReg(NewReg, RegState::Define)
|
||||
.addReg(DefReg);
|
||||
.addReg(DefReg, getUndefRegState(DefMO.isDead()));
|
||||
Op.setReg(TeeReg);
|
||||
Def->getOperand(0).setReg(DefReg);
|
||||
DefMO.setReg(DefReg);
|
||||
LIS.InsertMachineInstrInMaps(*Tee);
|
||||
LIS.removeInterval(Reg);
|
||||
LIS.createAndComputeVirtRegInterval(NewReg);
|
||||
|
@ -115,9 +115,11 @@ static bool ReplaceDominatedUses(MachineBasicBlock &MBB, MachineInstr &MI,
|
||||
O.setReg(ToReg);
|
||||
|
||||
// If the store's def was previously dead, it is no longer.
|
||||
MI.getOperand(0).setIsDead(false);
|
||||
if (!O.isUndef()) {
|
||||
MI.getOperand(0).setIsDead(false);
|
||||
|
||||
Indices.push_back(WhereIdx.getRegSlot());
|
||||
Indices.push_back(WhereIdx.getRegSlot());
|
||||
}
|
||||
}
|
||||
|
||||
if (Changed) {
|
||||
|
@ -1,4 +1,5 @@
|
||||
; RUN: llc < %s -asm-verbose=false | FileCheck %s
|
||||
; RUN: llc < %s -asm-verbose=false -fast-isel -fast-isel-abort=1 | FileCheck %s
|
||||
|
||||
; Test that basic call operations assemble as expected.
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
; RUN: llc < %s -asm-verbose=false | FileCheck %s
|
||||
; RUN: llc < %s -asm-verbose=false -fast-isel | FileCheck %s
|
||||
; RUN: llc < %s -asm-verbose=false -fast-isel -fast-isel-abort=1 | FileCheck %s
|
||||
|
||||
; Test that wasm select instruction is selected from LLVM select instruction.
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user