forked from OSchip/llvm-project
[WebAssembly] Fast-isel support for calls, arguments, and selects.
llvm-svn: 269273
This commit is contained in:
parent
1fb10e846a
commit
33e694a807
|
@ -12,10 +12,13 @@
|
||||||
/// class. Some of the target-specific code is generated by tablegen in the file
|
/// class. Some of the target-specific code is generated by tablegen in the file
|
||||||
/// WebAssemblyGenFastISel.inc, which is #included here.
|
/// WebAssemblyGenFastISel.inc, which is #included here.
|
||||||
///
|
///
|
||||||
|
/// TODO: kill flags
|
||||||
|
///
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
#include "WebAssembly.h"
|
#include "WebAssembly.h"
|
||||||
#include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
|
#include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
|
||||||
|
#include "WebAssemblyMachineFunctionInfo.h"
|
||||||
#include "WebAssemblySubtarget.h"
|
#include "WebAssemblySubtarget.h"
|
||||||
#include "WebAssemblyTargetMachine.h"
|
#include "WebAssemblyTargetMachine.h"
|
||||||
#include "llvm/Analysis/BranchProbabilityInfo.h"
|
#include "llvm/Analysis/BranchProbabilityInfo.h"
|
||||||
|
@ -104,10 +107,12 @@ private:
|
||||||
case MVT::i1:
|
case MVT::i1:
|
||||||
case MVT::i8:
|
case MVT::i8:
|
||||||
case MVT::i16:
|
case MVT::i16:
|
||||||
case MVT::i32:
|
|
||||||
return MVT::i32;
|
return MVT::i32;
|
||||||
|
case MVT::i32:
|
||||||
case MVT::i64:
|
case MVT::i64:
|
||||||
return MVT::i64;
|
case MVT::f32:
|
||||||
|
case MVT::f64:
|
||||||
|
return VT;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -118,7 +123,7 @@ private:
|
||||||
void addLoadStoreOperands(const Address &Addr, const MachineInstrBuilder &MIB,
|
void addLoadStoreOperands(const Address &Addr, const MachineInstrBuilder &MIB,
|
||||||
MachineMemOperand *MMO);
|
MachineMemOperand *MMO);
|
||||||
unsigned maskI1Value(unsigned Reg, const Value *V);
|
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,
|
unsigned zeroExtendToI32(unsigned Reg, const Value *V,
|
||||||
MVT::SimpleValueType From);
|
MVT::SimpleValueType From);
|
||||||
unsigned signExtendToI32(unsigned Reg, const Value *V,
|
unsigned signExtendToI32(unsigned Reg, const Value *V,
|
||||||
|
@ -133,12 +138,17 @@ private:
|
||||||
unsigned getRegForSignedValue(const Value *V);
|
unsigned getRegForSignedValue(const Value *V);
|
||||||
unsigned getRegForPromotedValue(const Value *V, bool IsSigned);
|
unsigned getRegForPromotedValue(const Value *V, bool IsSigned);
|
||||||
unsigned notValue(unsigned Reg);
|
unsigned notValue(unsigned Reg);
|
||||||
|
unsigned copyValue(unsigned Reg);
|
||||||
|
|
||||||
// Backend specific FastISel code.
|
// Backend specific FastISel code.
|
||||||
unsigned fastMaterializeAlloca(const AllocaInst *AI) override;
|
unsigned fastMaterializeAlloca(const AllocaInst *AI) override;
|
||||||
unsigned fastMaterializeConstant(const Constant *C) override;
|
unsigned fastMaterializeConstant(const Constant *C) override;
|
||||||
|
bool fastLowerArguments() override;
|
||||||
|
|
||||||
// Selection routines.
|
// Selection routines.
|
||||||
|
bool selectCall(const Instruction *I);
|
||||||
|
bool selectSelect(const Instruction *I);
|
||||||
|
bool selectTrunc(const Instruction *I);
|
||||||
bool selectZExt(const Instruction *I);
|
bool selectZExt(const Instruction *I);
|
||||||
bool selectSExt(const Instruction *I);
|
bool selectSExt(const Instruction *I);
|
||||||
bool selectICmp(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();
|
uint64_t TmpOffset = Addr.getOffset();
|
||||||
// Iterate through the GEP folding the constants into offsets where
|
// Iterate through the GEP folding the constants into offsets where
|
||||||
// we can.
|
// 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) {
|
GTI != E; ++GTI) {
|
||||||
const Value *Op = GTI.getOperand();
|
const Value *Op = GTI.getOperand();
|
||||||
if (StructType *STy = dyn_cast<StructType>(*GTI)) {
|
if (StructType *STy = dyn_cast<StructType>(*GTI)) {
|
||||||
|
@ -236,6 +246,11 @@ bool WebAssemblyFastISel::computeAddress(const Value *Obj, Address &Addr) {
|
||||||
TmpOffset += CI->getSExtValue() * S;
|
TmpOffset += CI->getSExtValue() * S;
|
||||||
break;
|
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)) {
|
if (canFoldAddIntoGEP(U, Op)) {
|
||||||
// A compatible add with a constant operand. Fold the constant.
|
// A compatible add with a constant operand. Fold the constant.
|
||||||
ConstantInt *CI =
|
ConstantInt *CI =
|
||||||
|
@ -347,7 +362,20 @@ unsigned WebAssemblyFastISel::maskI1Value(unsigned Reg, const Value *V) {
|
||||||
return zeroExtendToI32(Reg, V, MVT::i1);
|
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);
|
return maskI1Value(getRegForValue(V), V);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -357,11 +385,16 @@ unsigned WebAssemblyFastISel::zeroExtendToI32(unsigned Reg, const Value *V,
|
||||||
case MVT::i1:
|
case MVT::i1:
|
||||||
// If the value is naturally an i1, we don't need to mask it.
|
// If the value is naturally an i1, we don't need to mask it.
|
||||||
// TODO: Recursively examine selects, phis, and, or, xor, constants.
|
// TODO: Recursively examine selects, phis, and, or, xor, constants.
|
||||||
if (From == MVT::i1 && V != nullptr && isa<CmpInst>(V))
|
if (From == MVT::i1 && V != nullptr) {
|
||||||
return Reg;
|
if (isa<CmpInst>(V) ||
|
||||||
|
(isa<Argument>(V) && cast<Argument>(V)->hasZExtAttr()))
|
||||||
|
return copyValue(Reg);
|
||||||
|
}
|
||||||
|
case MVT::i8:
|
||||||
|
case MVT::i16:
|
||||||
break;
|
break;
|
||||||
case MVT::i32:
|
case MVT::i32:
|
||||||
return Reg;
|
return copyValue(Reg);
|
||||||
default:
|
default:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -388,9 +421,9 @@ unsigned WebAssemblyFastISel::signExtendToI32(unsigned Reg, const Value *V,
|
||||||
case MVT::i16:
|
case MVT::i16:
|
||||||
break;
|
break;
|
||||||
case MVT::i32:
|
case MVT::i32:
|
||||||
return Reg;
|
return copyValue(Reg);
|
||||||
default:
|
default:
|
||||||
return false;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned Imm = createResultReg(&WebAssembly::I32RegClass);
|
unsigned Imm = createResultReg(&WebAssembly::I32RegClass);
|
||||||
|
@ -418,7 +451,7 @@ unsigned WebAssemblyFastISel::zeroExtend(unsigned Reg, const Value *V,
|
||||||
MVT::SimpleValueType To) {
|
MVT::SimpleValueType To) {
|
||||||
if (To == MVT::i64) {
|
if (To == MVT::i64) {
|
||||||
if (From == MVT::i64)
|
if (From == MVT::i64)
|
||||||
return Reg;
|
return copyValue(Reg);
|
||||||
|
|
||||||
Reg = zeroExtendToI32(Reg, V, From);
|
Reg = zeroExtendToI32(Reg, V, From);
|
||||||
|
|
||||||
|
@ -429,21 +462,6 @@ unsigned WebAssemblyFastISel::zeroExtend(unsigned Reg, const Value *V,
|
||||||
return Result;
|
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);
|
return zeroExtendToI32(Reg, V, From);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -452,7 +470,7 @@ unsigned WebAssemblyFastISel::signExtend(unsigned Reg, const Value *V,
|
||||||
MVT::SimpleValueType To) {
|
MVT::SimpleValueType To) {
|
||||||
if (To == MVT::i64) {
|
if (To == MVT::i64) {
|
||||||
if (From == MVT::i64)
|
if (From == MVT::i64)
|
||||||
return Reg;
|
return copyValue(Reg);
|
||||||
|
|
||||||
Reg = signExtendToI32(Reg, V, From);
|
Reg = signExtendToI32(Reg, V, From);
|
||||||
|
|
||||||
|
@ -463,17 +481,6 @@ unsigned WebAssemblyFastISel::signExtend(unsigned Reg, const Value *V,
|
||||||
return Result;
|
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);
|
return signExtendToI32(Reg, V, From);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -496,6 +503,8 @@ unsigned WebAssemblyFastISel::getRegForPromotedValue(const Value *V,
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned WebAssemblyFastISel::notValue(unsigned Reg) {
|
unsigned WebAssemblyFastISel::notValue(unsigned Reg) {
|
||||||
|
assert(MRI.getRegClass(Reg) == &WebAssembly::I32RegClass);
|
||||||
|
|
||||||
unsigned NotReg = createResultReg(&WebAssembly::I32RegClass);
|
unsigned NotReg = createResultReg(&WebAssembly::I32RegClass);
|
||||||
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
|
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
|
||||||
TII.get(WebAssembly::EQZ_I32), NotReg)
|
TII.get(WebAssembly::EQZ_I32), NotReg)
|
||||||
|
@ -503,6 +512,14 @@ unsigned WebAssemblyFastISel::notValue(unsigned Reg) {
|
||||||
return NotReg;
|
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) {
|
unsigned WebAssemblyFastISel::fastMaterializeAlloca(const AllocaInst *AI) {
|
||||||
DenseMap<const AllocaInst *, int>::iterator SI =
|
DenseMap<const AllocaInst *, int>::iterator SI =
|
||||||
FuncInfo.StaticAllocaMap.find(AI);
|
FuncInfo.StaticAllocaMap.find(AI);
|
||||||
|
@ -524,25 +541,259 @@ unsigned WebAssemblyFastISel::fastMaterializeAlloca(const AllocaInst *AI) {
|
||||||
|
|
||||||
unsigned WebAssemblyFastISel::fastMaterializeConstant(const Constant *C) {
|
unsigned WebAssemblyFastISel::fastMaterializeConstant(const Constant *C) {
|
||||||
if (const GlobalValue *GV = dyn_cast<GlobalValue>(C)) {
|
if (const GlobalValue *GV = dyn_cast<GlobalValue>(C)) {
|
||||||
unsigned Reg = createResultReg(Subtarget->hasAddr64() ?
|
unsigned ResultReg = createResultReg(Subtarget->hasAddr64() ?
|
||||||
&WebAssembly::I64RegClass :
|
&WebAssembly::I64RegClass :
|
||||||
&WebAssembly::I32RegClass);
|
&WebAssembly::I32RegClass);
|
||||||
unsigned Opc = Subtarget->hasAddr64() ?
|
unsigned Opc = Subtarget->hasAddr64() ?
|
||||||
WebAssembly::CONST_I64 :
|
WebAssembly::CONST_I64 :
|
||||||
WebAssembly::CONST_I32;
|
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);
|
.addGlobalAddress(GV);
|
||||||
return Reg;
|
return ResultReg;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Let target-independent code handle it.
|
// Let target-independent code handle it.
|
||||||
return 0;
|
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) {
|
bool WebAssemblyFastISel::selectZExt(const Instruction *I) {
|
||||||
const ZExtInst *ZExt = cast<ZExtInst>(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)
|
if (Reg == 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -553,7 +804,10 @@ bool WebAssemblyFastISel::selectZExt(const Instruction *I) {
|
||||||
bool WebAssemblyFastISel::selectSExt(const Instruction *I) {
|
bool WebAssemblyFastISel::selectSExt(const Instruction *I) {
|
||||||
const SExtInst *SExt = cast<SExtInst>(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)
|
if (Reg == 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -694,6 +948,13 @@ bool WebAssemblyFastISel::selectBitCast(const Instruction *I) {
|
||||||
EVT RetVT = TLI.getValueType(DL, I->getType());
|
EVT RetVT = TLI.getValueType(DL, I->getType());
|
||||||
if (!VT.isSimple() || !RetVT.isSimple())
|
if (!VT.isSimple() || !RetVT.isSimple())
|
||||||
return false;
|
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(),
|
unsigned Reg = fastEmit_ISD_BITCAST_r(VT.getSimpleVT(), RetVT.getSimpleVT(),
|
||||||
getRegForValue(I->getOperand(0)),
|
getRegForValue(I->getOperand(0)),
|
||||||
I->getOperand(0)->hasOneUse());
|
I->getOperand(0)->hasOneUse());
|
||||||
|
@ -831,14 +1092,13 @@ bool WebAssemblyFastISel::selectBr(const Instruction *I) {
|
||||||
MachineBasicBlock *TBB = FuncInfo.MBBMap[Br->getSuccessor(0)];
|
MachineBasicBlock *TBB = FuncInfo.MBBMap[Br->getSuccessor(0)];
|
||||||
MachineBasicBlock *FBB = FuncInfo.MBBMap[Br->getSuccessor(1)];
|
MachineBasicBlock *FBB = FuncInfo.MBBMap[Br->getSuccessor(1)];
|
||||||
|
|
||||||
Value *Cond = Br->getCondition();
|
bool Not;
|
||||||
unsigned Opc = WebAssembly::BR_IF;
|
unsigned CondReg = getRegForI1Value(Br->getCondition(), Not);
|
||||||
if (BinaryOperator::isNot(Cond)) {
|
|
||||||
Cond = BinaryOperator::getNotArgument(Cond);
|
unsigned Opc = WebAssembly::BR_IF;
|
||||||
Opc = WebAssembly::BR_UNLESS;
|
if (Not)
|
||||||
}
|
Opc = WebAssembly::BR_UNLESS;
|
||||||
|
|
||||||
unsigned CondReg = getRegForI1Value(Cond);
|
|
||||||
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc))
|
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc))
|
||||||
.addMBB(TBB)
|
.addMBB(TBB)
|
||||||
.addReg(CondReg);
|
.addReg(CondReg);
|
||||||
|
@ -874,7 +1134,14 @@ bool WebAssemblyFastISel::selectRet(const Instruction *I) {
|
||||||
default: return false;
|
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);
|
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc)).addReg(Reg);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -887,6 +1154,12 @@ bool WebAssemblyFastISel::selectUnreachable(const Instruction *I) {
|
||||||
|
|
||||||
bool WebAssemblyFastISel::fastSelectInstruction(const Instruction *I) {
|
bool WebAssemblyFastISel::fastSelectInstruction(const Instruction *I) {
|
||||||
switch (I->getOpcode()) {
|
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::ZExt: return selectZExt(I);
|
||||||
case Instruction::SExt: return selectSExt(I);
|
case Instruction::SExt: return selectSExt(I);
|
||||||
case Instruction::ICmp: return selectICmp(I);
|
case Instruction::ICmp: return selectICmp(I);
|
||||||
|
|
|
@ -297,13 +297,14 @@ static MachineInstr *MoveAndTeeForMultiUse(
|
||||||
unsigned NewReg = MRI.createVirtualRegister(RegClass);
|
unsigned NewReg = MRI.createVirtualRegister(RegClass);
|
||||||
unsigned TeeReg = MRI.createVirtualRegister(RegClass);
|
unsigned TeeReg = MRI.createVirtualRegister(RegClass);
|
||||||
unsigned DefReg = MRI.createVirtualRegister(RegClass);
|
unsigned DefReg = MRI.createVirtualRegister(RegClass);
|
||||||
|
MachineOperand &DefMO = Def->getOperand(0);
|
||||||
MRI.replaceRegWith(Reg, NewReg);
|
MRI.replaceRegWith(Reg, NewReg);
|
||||||
MachineInstr *Tee = BuildMI(MBB, Insert, Insert->getDebugLoc(),
|
MachineInstr *Tee = BuildMI(MBB, Insert, Insert->getDebugLoc(),
|
||||||
TII->get(GetTeeLocalOpcode(RegClass)), TeeReg)
|
TII->get(GetTeeLocalOpcode(RegClass)), TeeReg)
|
||||||
.addReg(NewReg, RegState::Define)
|
.addReg(NewReg, RegState::Define)
|
||||||
.addReg(DefReg);
|
.addReg(DefReg, getUndefRegState(DefMO.isDead()));
|
||||||
Op.setReg(TeeReg);
|
Op.setReg(TeeReg);
|
||||||
Def->getOperand(0).setReg(DefReg);
|
DefMO.setReg(DefReg);
|
||||||
LIS.InsertMachineInstrInMaps(*Tee);
|
LIS.InsertMachineInstrInMaps(*Tee);
|
||||||
LIS.removeInterval(Reg);
|
LIS.removeInterval(Reg);
|
||||||
LIS.createAndComputeVirtRegInterval(NewReg);
|
LIS.createAndComputeVirtRegInterval(NewReg);
|
||||||
|
|
|
@ -115,9 +115,11 @@ static bool ReplaceDominatedUses(MachineBasicBlock &MBB, MachineInstr &MI,
|
||||||
O.setReg(ToReg);
|
O.setReg(ToReg);
|
||||||
|
|
||||||
// If the store's def was previously dead, it is no longer.
|
// 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) {
|
if (Changed) {
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
; RUN: llc < %s -asm-verbose=false | FileCheck %s
|
; 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.
|
; 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 | 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.
|
; Test that wasm select instruction is selected from LLVM select instruction.
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue