Commit fbdd2440 by Jan Voung

Factor out legalization of undef, and handle more cases for ARM.

By factoring out legalizeUndef(), we can use the same logic in prelowerPhis which may help if we ever change the value used (though if we switch from zero-ing out regs to using uninitialized regs, it'll take more work -- e.g., can't return a 64-bit reg). For x86, use legalizeUndef where it's clear that the value is immediately fed to loOperand/hiOperand then another legalize() call. Otherwise, leave the general X = legalize(X); alone where the code is counting on that being the sole legalization. For x86 legalize(const64) is a pass-through, which can then be passed to loOperand/hiOperand nicely. However, for ARM, legalize(const64) may end up trying to copy the const64 to a register, but we don't have 64-bit registers. Instead do legalizeUndef(X) where x86 would have just done legalize(X). This happens to work because legalizeUndef doesn't try to copy to reg, and we immediately pass the result to loOperand/hiOperand() which then passes the result to a real legalization call. Add a few more undef tests. BUG= https://code.google.com/p/nativeclient/issues/detail?id=4076 R=stichnot@chromium.org Review URL: https://codereview.chromium.org/1233903002 .
parent 728c1d40
...@@ -863,14 +863,14 @@ Operand *TargetARM32::loOperand(Operand *Operand) { ...@@ -863,14 +863,14 @@ Operand *TargetARM32::loOperand(Operand *Operand) {
assert(Operand->getType() == IceType_i64); assert(Operand->getType() == IceType_i64);
if (Operand->getType() != IceType_i64) if (Operand->getType() != IceType_i64)
return Operand; return Operand;
if (Variable *Var = llvm::dyn_cast<Variable>(Operand)) { if (auto *Var = llvm::dyn_cast<Variable>(Operand)) {
split64(Var); split64(Var);
return Var->getLo(); return Var->getLo();
} }
if (ConstantInteger64 *Const = llvm::dyn_cast<ConstantInteger64>(Operand)) { if (auto *Const = llvm::dyn_cast<ConstantInteger64>(Operand)) {
return Ctx->getConstantInt32(static_cast<uint32_t>(Const->getValue())); return Ctx->getConstantInt32(static_cast<uint32_t>(Const->getValue()));
} }
if (OperandARM32Mem *Mem = llvm::dyn_cast<OperandARM32Mem>(Operand)) { if (auto *Mem = llvm::dyn_cast<OperandARM32Mem>(Operand)) {
// Conservatively disallow memory operands with side-effects (pre/post // Conservatively disallow memory operands with side-effects (pre/post
// increment) in case of duplication. // increment) in case of duplication.
assert(Mem->getAddrMode() == OperandARM32Mem::Offset || assert(Mem->getAddrMode() == OperandARM32Mem::Offset ||
...@@ -892,15 +892,15 @@ Operand *TargetARM32::hiOperand(Operand *Operand) { ...@@ -892,15 +892,15 @@ Operand *TargetARM32::hiOperand(Operand *Operand) {
assert(Operand->getType() == IceType_i64); assert(Operand->getType() == IceType_i64);
if (Operand->getType() != IceType_i64) if (Operand->getType() != IceType_i64)
return Operand; return Operand;
if (Variable *Var = llvm::dyn_cast<Variable>(Operand)) { if (auto *Var = llvm::dyn_cast<Variable>(Operand)) {
split64(Var); split64(Var);
return Var->getHi(); return Var->getHi();
} }
if (ConstantInteger64 *Const = llvm::dyn_cast<ConstantInteger64>(Operand)) { if (auto *Const = llvm::dyn_cast<ConstantInteger64>(Operand)) {
return Ctx->getConstantInt32( return Ctx->getConstantInt32(
static_cast<uint32_t>(Const->getValue() >> 32)); static_cast<uint32_t>(Const->getValue() >> 32));
} }
if (OperandARM32Mem *Mem = llvm::dyn_cast<OperandARM32Mem>(Operand)) { if (auto *Mem = llvm::dyn_cast<OperandARM32Mem>(Operand)) {
// Conservatively disallow memory operands with side-effects // Conservatively disallow memory operands with side-effects
// in case of duplication. // in case of duplication.
assert(Mem->getAddrMode() == OperandARM32Mem::Offset || assert(Mem->getAddrMode() == OperandARM32Mem::Offset ||
...@@ -1012,7 +1012,7 @@ void TargetARM32::lowerAlloca(const InstAlloca *Inst) { ...@@ -1012,7 +1012,7 @@ void TargetARM32::lowerAlloca(const InstAlloca *Inst) {
} else { } else {
// Non-constant sizes need to be adjusted to the next highest // Non-constant sizes need to be adjusted to the next highest
// multiple of the required alignment at runtime. // multiple of the required alignment at runtime.
TotalSize = legalize(TotalSize); TotalSize = legalize(TotalSize, Legal_Reg | Legal_Flex);
Variable *T = makeReg(IceType_i32); Variable *T = makeReg(IceType_i32);
_mov(T, TotalSize); _mov(T, TotalSize);
Operand *AddAmount = legalize(Ctx->getConstantInt32(Alignment - 1)); Operand *AddAmount = legalize(Ctx->getConstantInt32(Alignment - 1));
...@@ -1101,8 +1101,8 @@ void TargetARM32::lowerArithmetic(const InstArithmetic *Inst) { ...@@ -1101,8 +1101,8 @@ void TargetARM32::lowerArithmetic(const InstArithmetic *Inst) {
// Or it may be the case that the operands aren't swapped, but the // Or it may be the case that the operands aren't swapped, but the
// bits can be flipped and a different operation applied. // bits can be flipped and a different operation applied.
// E.g., use BIC (bit clear) instead of AND for some masks. // E.g., use BIC (bit clear) instead of AND for some masks.
Operand *Src0 = Inst->getSrc(0); Operand *Src0 = legalizeUndef(Inst->getSrc(0));
Operand *Src1 = Inst->getSrc(1); Operand *Src1 = legalizeUndef(Inst->getSrc(1));
if (Dest->getType() == IceType_i64) { if (Dest->getType() == IceType_i64) {
// These helper-call-involved instructions are lowered in this // These helper-call-involved instructions are lowered in this
// separate switch. This is because we would otherwise assume that // separate switch. This is because we would otherwise assume that
...@@ -1458,9 +1458,9 @@ void TargetARM32::lowerAssign(const InstAssign *Inst) { ...@@ -1458,9 +1458,9 @@ void TargetARM32::lowerAssign(const InstAssign *Inst) {
Operand *Src0 = Inst->getSrc(0); Operand *Src0 = Inst->getSrc(0);
assert(Dest->getType() == Src0->getType()); assert(Dest->getType() == Src0->getType());
if (Dest->getType() == IceType_i64) { if (Dest->getType() == IceType_i64) {
Src0 = legalize(Src0); Src0 = legalizeUndef(Src0);
Operand *Src0Lo = loOperand(Src0); Operand *Src0Lo = legalize(loOperand(Src0), Legal_Reg | Legal_Flex);
Operand *Src0Hi = hiOperand(Src0); Operand *Src0Hi = legalize(hiOperand(Src0), Legal_Reg | Legal_Flex);
Variable *DestLo = llvm::cast<Variable>(loOperand(Dest)); Variable *DestLo = llvm::cast<Variable>(loOperand(Dest));
Variable *DestHi = llvm::cast<Variable>(hiOperand(Dest)); Variable *DestHi = llvm::cast<Variable>(hiOperand(Dest));
Variable *T_Lo = nullptr, *T_Hi = nullptr; Variable *T_Lo = nullptr, *T_Hi = nullptr;
...@@ -1523,7 +1523,7 @@ void TargetARM32::lowerCall(const InstCall *Instr) { ...@@ -1523,7 +1523,7 @@ void TargetARM32::lowerCall(const InstCall *Instr) {
// Classify each argument operand according to the location where the // Classify each argument operand according to the location where the
// argument is passed. // argument is passed.
for (SizeT i = 0, NumArgs = Instr->getNumArgs(); i < NumArgs; ++i) { for (SizeT i = 0, NumArgs = Instr->getNumArgs(); i < NumArgs; ++i) {
Operand *Arg = Instr->getArg(i); Operand *Arg = legalizeUndef(Instr->getArg(i));
Type Ty = Arg->getType(); Type Ty = Arg->getType();
bool InRegs = false; bool InRegs = false;
if (isVectorType(Ty)) { if (isVectorType(Ty)) {
...@@ -1703,7 +1703,7 @@ void TargetARM32::lowerCall(const InstCall *Instr) { ...@@ -1703,7 +1703,7 @@ void TargetARM32::lowerCall(const InstCall *Instr) {
void TargetARM32::lowerCast(const InstCast *Inst) { void TargetARM32::lowerCast(const InstCast *Inst) {
InstCast::OpKind CastKind = Inst->getCastKind(); InstCast::OpKind CastKind = Inst->getCastKind();
Variable *Dest = Inst->getDest(); Variable *Dest = Inst->getDest();
Operand *Src0 = Inst->getSrc(0); Operand *Src0 = legalizeUndef(Inst->getSrc(0));
switch (CastKind) { switch (CastKind) {
default: default:
Func->setError("Cast type not supported"); Func->setError("Cast type not supported");
...@@ -1808,7 +1808,6 @@ void TargetARM32::lowerCast(const InstCast *Inst) { ...@@ -1808,7 +1808,6 @@ void TargetARM32::lowerCast(const InstCast *Inst) {
if (isVectorType(Dest->getType())) { if (isVectorType(Dest->getType())) {
UnimplementedError(Func->getContext()->getFlags()); UnimplementedError(Func->getContext()->getFlags());
} else { } else {
Operand *Src0 = Inst->getSrc(0);
if (Src0->getType() == IceType_i64) if (Src0->getType() == IceType_i64)
Src0 = loOperand(Src0); Src0 = loOperand(Src0);
Operand *Src0RF = legalize(Src0, Legal_Reg | Legal_Flex); Operand *Src0RF = legalize(Src0, Legal_Reg | Legal_Flex);
...@@ -1866,8 +1865,8 @@ void TargetARM32::lowerFcmp(const InstFcmp *Inst) { ...@@ -1866,8 +1865,8 @@ void TargetARM32::lowerFcmp(const InstFcmp *Inst) {
void TargetARM32::lowerIcmp(const InstIcmp *Inst) { void TargetARM32::lowerIcmp(const InstIcmp *Inst) {
Variable *Dest = Inst->getDest(); Variable *Dest = Inst->getDest();
Operand *Src0 = Inst->getSrc(0); Operand *Src0 = legalizeUndef(Inst->getSrc(0));
Operand *Src1 = Inst->getSrc(1); Operand *Src1 = legalizeUndef(Inst->getSrc(1));
if (isVectorType(Dest->getType())) { if (isVectorType(Dest->getType())) {
UnimplementedError(Func->getContext()->getFlags()); UnimplementedError(Func->getContext()->getFlags());
...@@ -2036,6 +2035,7 @@ void TargetARM32::lowerIntrinsicCall(const InstIntrinsicCall *Instr) { ...@@ -2036,6 +2035,7 @@ void TargetARM32::lowerIntrinsicCall(const InstIntrinsicCall *Instr) {
Operand *Val = Instr->getArg(0); Operand *Val = Instr->getArg(0);
Type Ty = Val->getType(); Type Ty = Val->getType();
if (Ty == IceType_i64) { if (Ty == IceType_i64) {
Val = legalizeUndef(Val);
Variable *Val_Lo = legalizeToVar(loOperand(Val)); Variable *Val_Lo = legalizeToVar(loOperand(Val));
Variable *Val_Hi = legalizeToVar(hiOperand(Val)); Variable *Val_Hi = legalizeToVar(hiOperand(Val));
Variable *T_Lo = makeReg(IceType_i32); Variable *T_Lo = makeReg(IceType_i32);
...@@ -2088,6 +2088,7 @@ void TargetARM32::lowerIntrinsicCall(const InstIntrinsicCall *Instr) { ...@@ -2088,6 +2088,7 @@ void TargetARM32::lowerIntrinsicCall(const InstIntrinsicCall *Instr) {
Variable *ValLoR; Variable *ValLoR;
Variable *ValHiR = nullptr; Variable *ValHiR = nullptr;
if (Val->getType() == IceType_i64) { if (Val->getType() == IceType_i64) {
Val = legalizeUndef(Val);
ValLoR = legalizeToVar(loOperand(Val)); ValLoR = legalizeToVar(loOperand(Val));
ValHiR = legalizeToVar(hiOperand(Val)); ValHiR = legalizeToVar(hiOperand(Val));
} else { } else {
...@@ -2102,6 +2103,7 @@ void TargetARM32::lowerIntrinsicCall(const InstIntrinsicCall *Instr) { ...@@ -2102,6 +2103,7 @@ void TargetARM32::lowerIntrinsicCall(const InstIntrinsicCall *Instr) {
Variable *ValLoR; Variable *ValLoR;
Variable *ValHiR = nullptr; Variable *ValHiR = nullptr;
if (Val->getType() == IceType_i64) { if (Val->getType() == IceType_i64) {
Val = legalizeUndef(Val);
ValLoR = legalizeToVar(loOperand(Val)); ValLoR = legalizeToVar(loOperand(Val));
ValHiR = legalizeToVar(hiOperand(Val)); ValHiR = legalizeToVar(hiOperand(Val));
Variable *TLo = makeReg(IceType_i32); Variable *TLo = makeReg(IceType_i32);
...@@ -2268,6 +2270,7 @@ void TargetARM32::lowerRet(const InstRet *Inst) { ...@@ -2268,6 +2270,7 @@ void TargetARM32::lowerRet(const InstRet *Inst) {
if (Inst->hasRetValue()) { if (Inst->hasRetValue()) {
Operand *Src0 = Inst->getRetValue(); Operand *Src0 = Inst->getRetValue();
if (Src0->getType() == IceType_i64) { if (Src0->getType() == IceType_i64) {
Src0 = legalizeUndef(Src0);
Variable *R0 = legalizeToVar(loOperand(Src0), RegARM32::Reg_r0); Variable *R0 = legalizeToVar(loOperand(Src0), RegARM32::Reg_r0);
Variable *R1 = legalizeToVar(hiOperand(Src0), RegARM32::Reg_r1); Variable *R1 = legalizeToVar(hiOperand(Src0), RegARM32::Reg_r1);
Reg = R0; Reg = R0;
...@@ -2318,6 +2321,8 @@ void TargetARM32::lowerSelect(const InstSelect *Inst) { ...@@ -2318,6 +2321,8 @@ void TargetARM32::lowerSelect(const InstSelect *Inst) {
_cmp(CmpOpnd0, CmpOpnd1); _cmp(CmpOpnd0, CmpOpnd1);
CondARM32::Cond Cond = CondARM32::NE; CondARM32::Cond Cond = CondARM32::NE;
if (DestTy == IceType_i64) { if (DestTy == IceType_i64) {
SrcT = legalizeUndef(SrcT);
SrcF = legalizeUndef(SrcF);
// Set the low portion. // Set the low portion.
Variable *DestLo = llvm::cast<Variable>(loOperand(Dest)); Variable *DestLo = llvm::cast<Variable>(loOperand(Dest));
Variable *TLo = nullptr; Variable *TLo = nullptr;
...@@ -2351,6 +2356,7 @@ void TargetARM32::lowerStore(const InstStore *Inst) { ...@@ -2351,6 +2356,7 @@ void TargetARM32::lowerStore(const InstStore *Inst) {
Type Ty = NewAddr->getType(); Type Ty = NewAddr->getType();
if (Ty == IceType_i64) { if (Ty == IceType_i64) {
Value = legalizeUndef(Value);
Variable *ValueHi = legalizeToVar(hiOperand(Value)); Variable *ValueHi = legalizeToVar(hiOperand(Value));
Variable *ValueLo = legalizeToVar(loOperand(Value)); Variable *ValueLo = legalizeToVar(loOperand(Value));
_str(ValueHi, llvm::cast<OperandARM32Mem>(hiOperand(NewAddr))); _str(ValueHi, llvm::cast<OperandARM32Mem>(hiOperand(NewAddr)));
...@@ -2373,7 +2379,7 @@ void TargetARM32::lowerSwitch(const InstSwitch *Inst) { ...@@ -2373,7 +2379,7 @@ void TargetARM32::lowerSwitch(const InstSwitch *Inst) {
Operand *Src0 = Inst->getComparison(); Operand *Src0 = Inst->getComparison();
SizeT NumCases = Inst->getNumCases(); SizeT NumCases = Inst->getNumCases();
if (Src0->getType() == IceType_i64) { if (Src0->getType() == IceType_i64) {
// TODO(jvoung): handle and test undef for Src0 Src0 = legalizeUndef(Src0);
Variable *Src0Lo = legalizeToVar(loOperand(Src0)); Variable *Src0Lo = legalizeToVar(loOperand(Src0));
Variable *Src0Hi = legalizeToVar(hiOperand(Src0)); Variable *Src0Hi = legalizeToVar(hiOperand(Src0));
for (SizeT I = 0; I < NumCases; ++I) { for (SizeT I = 0; I < NumCases; ++I) {
...@@ -2444,6 +2450,7 @@ Variable *TargetARM32::copyToReg(Operand *Src, int32_t RegNum) { ...@@ -2444,6 +2450,7 @@ Variable *TargetARM32::copyToReg(Operand *Src, int32_t RegNum) {
Operand *TargetARM32::legalize(Operand *From, LegalMask Allowed, Operand *TargetARM32::legalize(Operand *From, LegalMask Allowed,
int32_t RegNum) { int32_t RegNum) {
Type Ty = From->getType();
// Assert that a physical register is allowed. To date, all calls // Assert that a physical register is allowed. To date, all calls
// to legalize() allow a physical register. Legal_Flex converts // to legalize() allow a physical register. Legal_Flex converts
// registers to the right type OperandARM32FlexReg as needed. // registers to the right type OperandARM32FlexReg as needed.
...@@ -2471,16 +2478,15 @@ Operand *TargetARM32::legalize(Operand *From, LegalMask Allowed, ...@@ -2471,16 +2478,15 @@ Operand *TargetARM32::legalize(Operand *From, LegalMask Allowed,
// There is only a reg +/- reg or reg + imm form. // There is only a reg +/- reg or reg + imm form.
// Figure out which to re-create. // Figure out which to re-create.
if (Mem->isRegReg()) { if (Mem->isRegReg()) {
Mem = OperandARM32Mem::create(Func, Mem->getType(), RegBase, RegIndex, Mem = OperandARM32Mem::create(Func, Ty, RegBase, RegIndex,
Mem->getShiftOp(), Mem->getShiftAmt(), Mem->getShiftOp(), Mem->getShiftAmt(),
Mem->getAddrMode()); Mem->getAddrMode());
} else { } else {
Mem = OperandARM32Mem::create(Func, Mem->getType(), RegBase, Mem = OperandARM32Mem::create(Func, Ty, RegBase, Mem->getOffset(),
Mem->getOffset(), Mem->getAddrMode()); Mem->getAddrMode());
} }
} }
if (!(Allowed & Legal_Mem)) { if (!(Allowed & Legal_Mem)) {
Type Ty = Mem->getType();
Variable *Reg = makeReg(Ty, RegNum); Variable *Reg = makeReg(Ty, RegNum);
_ldr(Reg, Mem); _ldr(Reg, Mem);
From = Reg; From = Reg;
...@@ -2510,17 +2516,14 @@ Operand *TargetARM32::legalize(Operand *From, LegalMask Allowed, ...@@ -2510,17 +2516,14 @@ Operand *TargetARM32::legalize(Operand *From, LegalMask Allowed,
if (llvm::isa<Constant>(From)) { if (llvm::isa<Constant>(From)) {
if (llvm::isa<ConstantUndef>(From)) { if (llvm::isa<ConstantUndef>(From)) {
// Lower undefs to zero. Another option is to lower undefs to an From = legalizeUndef(From, RegNum);
// uninitialized register; however, using an uninitialized register if (isVectorType(Ty))
// results in less predictable code. return From;
if (isVectorType(From->getType()))
return makeVectorOfZeros(From->getType(), RegNum);
From = Ctx->getConstantZero(From->getType());
} }
// There should be no constants of vector type (other than undef). // There should be no constants of vector type (other than undef).
assert(!isVectorType(From->getType())); assert(!isVectorType(Ty));
bool CanBeFlex = Allowed & Legal_Flex; bool CanBeFlex = Allowed & Legal_Flex;
if (auto C32 = llvm::dyn_cast<ConstantInteger32>(From)) { if (auto *C32 = llvm::dyn_cast<ConstantInteger32>(From)) {
uint32_t RotateAmt; uint32_t RotateAmt;
uint32_t Immed_8; uint32_t Immed_8;
uint32_t Value = static_cast<uint32_t>(C32->getValue()); uint32_t Value = static_cast<uint32_t>(C32->getValue());
...@@ -2530,19 +2533,16 @@ Operand *TargetARM32::legalize(Operand *From, LegalMask Allowed, ...@@ -2530,19 +2533,16 @@ Operand *TargetARM32::legalize(Operand *From, LegalMask Allowed,
// Also try the inverse and use MVN if possible. // Also try the inverse and use MVN if possible.
if (CanBeFlex && if (CanBeFlex &&
OperandARM32FlexImm::canHoldImm(Value, &RotateAmt, &Immed_8)) { OperandARM32FlexImm::canHoldImm(Value, &RotateAmt, &Immed_8)) {
return OperandARM32FlexImm::create(Func, From->getType(), Immed_8, return OperandARM32FlexImm::create(Func, Ty, Immed_8, RotateAmt);
RotateAmt);
} else if (CanBeFlex && OperandARM32FlexImm::canHoldImm( } else if (CanBeFlex && OperandARM32FlexImm::canHoldImm(
~Value, &RotateAmt, &Immed_8)) { ~Value, &RotateAmt, &Immed_8)) {
auto InvertedFlex = OperandARM32FlexImm::create(Func, From->getType(), auto InvertedFlex =
Immed_8, RotateAmt); OperandARM32FlexImm::create(Func, Ty, Immed_8, RotateAmt);
Type Ty = From->getType();
Variable *Reg = makeReg(Ty, RegNum); Variable *Reg = makeReg(Ty, RegNum);
_mvn(Reg, InvertedFlex); _mvn(Reg, InvertedFlex);
return Reg; return Reg;
} else { } else {
// Do a movw/movt to a register. // Do a movw/movt to a register.
Type Ty = From->getType();
Variable *Reg = makeReg(Ty, RegNum); Variable *Reg = makeReg(Ty, RegNum);
uint32_t UpperBits = (Value >> 16) & 0xFFFF; uint32_t UpperBits = (Value >> 16) & 0xFFFF;
_movw(Reg, _movw(Reg,
...@@ -2552,8 +2552,7 @@ Operand *TargetARM32::legalize(Operand *From, LegalMask Allowed, ...@@ -2552,8 +2552,7 @@ Operand *TargetARM32::legalize(Operand *From, LegalMask Allowed,
} }
return Reg; return Reg;
} }
} else if (auto C = llvm::dyn_cast<ConstantRelocatable>(From)) { } else if (auto *C = llvm::dyn_cast<ConstantRelocatable>(From)) {
Type Ty = From->getType();
Variable *Reg = makeReg(Ty, RegNum); Variable *Reg = makeReg(Ty, RegNum);
_movw(Reg, C); _movw(Reg, C);
_movt(Reg, C); _movt(Reg, C);
...@@ -2586,11 +2585,33 @@ Operand *TargetARM32::legalize(Operand *From, LegalMask Allowed, ...@@ -2586,11 +2585,33 @@ Operand *TargetARM32::legalize(Operand *From, LegalMask Allowed,
return From; return From;
} }
// Provide a trivial wrapper to legalize() for this common usage. /// Provide a trivial wrapper to legalize() for this common usage.
Variable *TargetARM32::legalizeToVar(Operand *From, int32_t RegNum) { Variable *TargetARM32::legalizeToVar(Operand *From, int32_t RegNum) {
return llvm::cast<Variable>(legalize(From, Legal_Reg, RegNum)); return llvm::cast<Variable>(legalize(From, Legal_Reg, RegNum));
} }
/// Legalize undef values to concrete values.
Operand *TargetARM32::legalizeUndef(Operand *From, int32_t RegNum) {
Type Ty = From->getType();
if (llvm::isa<ConstantUndef>(From)) {
// Lower undefs to zero. Another option is to lower undefs to an
// uninitialized register; however, using an uninitialized register
// results in less predictable code.
//
// If in the future the implementation is changed to lower undef
// values to uninitialized registers, a FakeDef will be needed:
// Context.insert(InstFakeDef::create(Func, Reg));
// This is in order to ensure that the live range of Reg is not
// overestimated. If the constant being lowered is a 64 bit value,
// then the result should be split and the lo and hi components will
// need to go in uninitialized registers.
if (isVectorType(Ty))
return makeVectorOfZeros(Ty, RegNum);
return Ctx->getConstantZero(Ty);
}
return From;
}
OperandARM32Mem *TargetARM32::formMemoryOperand(Operand *Operand, Type Ty) { OperandARM32Mem *TargetARM32::formMemoryOperand(Operand *Operand, Type Ty) {
OperandARM32Mem *Mem = llvm::dyn_cast<OperandARM32Mem>(Operand); OperandARM32Mem *Mem = llvm::dyn_cast<OperandARM32Mem>(Operand);
// It may be the case that address mode optimization already creates // It may be the case that address mode optimization already creates
......
...@@ -146,6 +146,7 @@ protected: ...@@ -146,6 +146,7 @@ protected:
Operand *legalize(Operand *From, LegalMask Allowed = Legal_All, Operand *legalize(Operand *From, LegalMask Allowed = Legal_All,
int32_t RegNum = Variable::NoRegister); int32_t RegNum = Variable::NoRegister);
Variable *legalizeToVar(Operand *From, int32_t RegNum = Variable::NoRegister); Variable *legalizeToVar(Operand *From, int32_t RegNum = Variable::NoRegister);
Operand *legalizeUndef(Operand *From, int32_t RegNum = Variable::NoRegister);
OperandARM32Mem *formMemoryOperand(Operand *Ptr, Type Ty); OperandARM32Mem *formMemoryOperand(Operand *Ptr, Type Ty);
Variable *makeReg(Type Ty, int32_t RegNum = Variable::NoRegister); Variable *makeReg(Type Ty, int32_t RegNum = Variable::NoRegister);
......
...@@ -230,6 +230,7 @@ protected: ...@@ -230,6 +230,7 @@ protected:
Operand *legalize(Operand *From, LegalMask Allowed = Legal_All, Operand *legalize(Operand *From, LegalMask Allowed = Legal_All,
int32_t RegNum = Variable::NoRegister); int32_t RegNum = Variable::NoRegister);
Variable *legalizeToVar(Operand *From, int32_t RegNum = Variable::NoRegister); Variable *legalizeToVar(Operand *From, int32_t RegNum = Variable::NoRegister);
Operand *legalizeUndef(Operand *From, int32_t RegNum = Variable::NoRegister);
/// Legalize the first source operand for use in the cmp instruction. /// Legalize the first source operand for use in the cmp instruction.
Operand *legalizeSrc0ForCmp(Operand *Src0, Operand *Src1); Operand *legalizeSrc0ForCmp(Operand *Src0, Operand *Src1);
/// Turn a pointer operand into a memory operand that can be /// Turn a pointer operand into a memory operand that can be
......
...@@ -1164,13 +1164,14 @@ Operand *TargetX86Base<Machine>::loOperand(Operand *Operand) { ...@@ -1164,13 +1164,14 @@ Operand *TargetX86Base<Machine>::loOperand(Operand *Operand) {
Operand->getType() == IceType_f64); Operand->getType() == IceType_f64);
if (Operand->getType() != IceType_i64 && Operand->getType() != IceType_f64) if (Operand->getType() != IceType_i64 && Operand->getType() != IceType_f64)
return Operand; return Operand;
if (Variable *Var = llvm::dyn_cast<Variable>(Operand)) { if (auto *Var = llvm::dyn_cast<Variable>(Operand)) {
split64(Var); split64(Var);
return Var->getLo(); return Var->getLo();
} }
if (ConstantInteger64 *Const = llvm::dyn_cast<ConstantInteger64>(Operand)) { if (auto *Const = llvm::dyn_cast<ConstantInteger64>(Operand)) {
ConstantInteger32 *ConstInt = llvm::dyn_cast<ConstantInteger32>( auto *ConstInt = llvm::dyn_cast<ConstantInteger32>(
Ctx->getConstantInt32(static_cast<int32_t>(Const->getValue()))); Ctx->getConstantInt32(static_cast<int32_t>(Const->getValue())));
// Check if we need to blind/pool the constant.
return legalize(ConstInt); return legalize(ConstInt);
} }
if (auto *Mem = llvm::dyn_cast<typename Traits::X86OperandMem>(Operand)) { if (auto *Mem = llvm::dyn_cast<typename Traits::X86OperandMem>(Operand)) {
...@@ -1192,25 +1193,23 @@ Operand *TargetX86Base<Machine>::hiOperand(Operand *Operand) { ...@@ -1192,25 +1193,23 @@ Operand *TargetX86Base<Machine>::hiOperand(Operand *Operand) {
Operand->getType() == IceType_f64); Operand->getType() == IceType_f64);
if (Operand->getType() != IceType_i64 && Operand->getType() != IceType_f64) if (Operand->getType() != IceType_i64 && Operand->getType() != IceType_f64)
return Operand; return Operand;
if (Variable *Var = llvm::dyn_cast<Variable>(Operand)) { if (auto *Var = llvm::dyn_cast<Variable>(Operand)) {
split64(Var); split64(Var);
return Var->getHi(); return Var->getHi();
} }
if (ConstantInteger64 *Const = llvm::dyn_cast<ConstantInteger64>(Operand)) { if (auto *Const = llvm::dyn_cast<ConstantInteger64>(Operand)) {
ConstantInteger32 *ConstInt = llvm::dyn_cast<ConstantInteger32>( auto *ConstInt = llvm::dyn_cast<ConstantInteger32>(
Ctx->getConstantInt32(static_cast<int32_t>(Const->getValue() >> 32))); Ctx->getConstantInt32(static_cast<int32_t>(Const->getValue() >> 32)));
// check if we need to blind/pool the constant // Check if we need to blind/pool the constant.
return legalize(ConstInt); return legalize(ConstInt);
} }
if (auto *Mem = llvm::dyn_cast<typename Traits::X86OperandMem>(Operand)) { if (auto *Mem = llvm::dyn_cast<typename Traits::X86OperandMem>(Operand)) {
Constant *Offset = Mem->getOffset(); Constant *Offset = Mem->getOffset();
if (Offset == nullptr) { if (Offset == nullptr) {
Offset = Ctx->getConstantInt32(4); Offset = Ctx->getConstantInt32(4);
} else if (ConstantInteger32 *IntOffset = } else if (auto *IntOffset = llvm::dyn_cast<ConstantInteger32>(Offset)) {
llvm::dyn_cast<ConstantInteger32>(Offset)) {
Offset = Ctx->getConstantInt32(4 + IntOffset->getValue()); Offset = Ctx->getConstantInt32(4 + IntOffset->getValue());
} else if (ConstantRelocatable *SymOffset = } else if (auto *SymOffset = llvm::dyn_cast<ConstantRelocatable>(Offset)) {
llvm::dyn_cast<ConstantRelocatable>(Offset)) {
assert(!Utils::WouldOverflowAdd(SymOffset->getOffset(), 4)); assert(!Utils::WouldOverflowAdd(SymOffset->getOffset(), 4));
Offset = Offset =
Ctx->getConstantSym(4 + SymOffset->getOffset(), SymOffset->getName(), Ctx->getConstantSym(4 + SymOffset->getOffset(), SymOffset->getName(),
...@@ -2453,7 +2452,7 @@ void TargetX86Base<Machine>::lowerCast(const InstCast *Inst) { ...@@ -2453,7 +2452,7 @@ void TargetX86Base<Machine>::lowerCast(const InstCast *Inst) {
_pand(T, OneMask); _pand(T, OneMask);
_movp(Dest, T); _movp(Dest, T);
} else { } else {
Operand *Src0 = Inst->getSrc(0); Operand *Src0 = legalizeUndef(Inst->getSrc(0));
if (Src0->getType() == IceType_i64) if (Src0->getType() == IceType_i64)
Src0 = loOperand(Src0); Src0 = loOperand(Src0);
Operand *Src0RM = legalize(Src0, Legal_Reg | Legal_Mem); Operand *Src0RM = legalize(Src0, Legal_Reg | Legal_Mem);
...@@ -3261,9 +3260,9 @@ void TargetX86Base<Machine>::lowerIntrinsicCall( ...@@ -3261,9 +3260,9 @@ void TargetX86Base<Machine>::lowerIntrinsicCall(
return; return;
} }
Variable *DestPrev = Instr->getDest(); Variable *DestPrev = Instr->getDest();
Operand *PtrToMem = Instr->getArg(0); Operand *PtrToMem = legalize(Instr->getArg(0));
Operand *Expected = Instr->getArg(1); Operand *Expected = legalize(Instr->getArg(1));
Operand *Desired = Instr->getArg(2); Operand *Desired = legalize(Instr->getArg(2));
if (tryOptimizedCmpxchgCmpBr(DestPrev, PtrToMem, Expected, Desired)) if (tryOptimizedCmpxchgCmpBr(DestPrev, PtrToMem, Expected, Desired))
return; return;
lowerAtomicCmpxchg(DestPrev, PtrToMem, Expected, Desired); lowerAtomicCmpxchg(DestPrev, PtrToMem, Expected, Desired);
...@@ -3397,6 +3396,7 @@ void TargetX86Base<Machine>::lowerIntrinsicCall( ...@@ -3397,6 +3396,7 @@ void TargetX86Base<Machine>::lowerIntrinsicCall(
// In 32-bit mode, bswap only works on 32-bit arguments, and the // In 32-bit mode, bswap only works on 32-bit arguments, and the
// argument must be a register. Use rotate left for 16-bit bswap. // argument must be a register. Use rotate left for 16-bit bswap.
if (Val->getType() == IceType_i64) { if (Val->getType() == IceType_i64) {
Val = legalizeUndef(Val);
Variable *T_Lo = legalizeToVar(loOperand(Val)); Variable *T_Lo = legalizeToVar(loOperand(Val));
Variable *T_Hi = legalizeToVar(hiOperand(Val)); Variable *T_Hi = legalizeToVar(hiOperand(Val));
Variable *DestLo = llvm::cast<Variable>(loOperand(Dest)); Variable *DestLo = llvm::cast<Variable>(loOperand(Dest));
...@@ -3411,9 +3411,9 @@ void TargetX86Base<Machine>::lowerIntrinsicCall( ...@@ -3411,9 +3411,9 @@ void TargetX86Base<Machine>::lowerIntrinsicCall(
_mov(Dest, T); _mov(Dest, T);
} else { } else {
assert(Val->getType() == IceType_i16); assert(Val->getType() == IceType_i16);
Val = legalize(Val);
Constant *Eight = Ctx->getConstantInt16(8); Constant *Eight = Ctx->getConstantInt16(8);
Variable *T = nullptr; Variable *T = nullptr;
Val = legalize(Val);
_mov(T, Val); _mov(T, Val);
_rol(T, Eight); _rol(T, Eight);
_mov(Dest, T); _mov(Dest, T);
...@@ -4411,6 +4411,8 @@ void TargetX86Base<Machine>::lowerSelect(const InstSelect *Inst) { ...@@ -4411,6 +4411,8 @@ void TargetX86Base<Machine>::lowerSelect(const InstSelect *Inst) {
Cond = InstX86Base<Machine>::getOppositeCondition(Cond); Cond = InstX86Base<Machine>::getOppositeCondition(Cond);
} }
if (DestTy == IceType_i64) { if (DestTy == IceType_i64) {
SrcT = legalizeUndef(SrcT);
SrcF = legalizeUndef(SrcF);
// Set the low portion. // Set the low portion.
Variable *DestLo = llvm::cast<Variable>(loOperand(Dest)); Variable *DestLo = llvm::cast<Variable>(loOperand(Dest));
Variable *TLo = nullptr; Variable *TLo = nullptr;
...@@ -4448,7 +4450,7 @@ void TargetX86Base<Machine>::lowerStore(const InstStore *Inst) { ...@@ -4448,7 +4450,7 @@ void TargetX86Base<Machine>::lowerStore(const InstStore *Inst) {
Type Ty = NewAddr->getType(); Type Ty = NewAddr->getType();
if (Ty == IceType_i64) { if (Ty == IceType_i64) {
Value = legalize(Value); Value = legalizeUndef(Value);
Operand *ValueHi = legalize(hiOperand(Value), Legal_Reg | Legal_Imm); Operand *ValueHi = legalize(hiOperand(Value), Legal_Reg | Legal_Imm);
Operand *ValueLo = legalize(loOperand(Value), Legal_Reg | Legal_Imm); Operand *ValueLo = legalize(loOperand(Value), Legal_Reg | Legal_Imm);
_store(ValueHi, _store(ValueHi,
...@@ -4497,7 +4499,7 @@ void TargetX86Base<Machine>::lowerSwitch(const InstSwitch *Inst) { ...@@ -4497,7 +4499,7 @@ void TargetX86Base<Machine>::lowerSwitch(const InstSwitch *Inst) {
Operand *Src0 = Inst->getComparison(); Operand *Src0 = Inst->getComparison();
SizeT NumCases = Inst->getNumCases(); SizeT NumCases = Inst->getNumCases();
if (Src0->getType() == IceType_i64) { if (Src0->getType() == IceType_i64) {
Src0 = legalize(Src0); // get Base/Index into physical registers Src0 = legalizeUndef(Src0);
Operand *Src0Lo = loOperand(Src0); Operand *Src0Lo = loOperand(Src0);
Operand *Src0Hi = hiOperand(Src0); Operand *Src0Hi = hiOperand(Src0);
if (NumCases >= 2) { if (NumCases >= 2) {
...@@ -4613,6 +4615,7 @@ void TargetX86Base<Machine>::lowerRMW( ...@@ -4613,6 +4615,7 @@ void TargetX86Base<Machine>::lowerRMW(
Type Ty = Src->getType(); Type Ty = Src->getType();
typename Traits::X86OperandMem *Addr = formMemoryOperand(RMW->getAddr(), Ty); typename Traits::X86OperandMem *Addr = formMemoryOperand(RMW->getAddr(), Ty);
if (Ty == IceType_i64) { if (Ty == IceType_i64) {
Src = legalizeUndef(Src);
Operand *SrcLo = legalize(loOperand(Src), Legal_Reg | Legal_Imm); Operand *SrcLo = legalize(loOperand(Src), Legal_Reg | Legal_Imm);
Operand *SrcHi = legalize(hiOperand(Src), Legal_Reg | Legal_Imm); Operand *SrcHi = legalize(hiOperand(Src), Legal_Reg | Legal_Imm);
typename Traits::X86OperandMem *AddrLo = typename Traits::X86OperandMem *AddrLo =
...@@ -4708,8 +4711,7 @@ template <class Machine> void TargetX86Base<Machine>::prelowerPhis() { ...@@ -4708,8 +4711,7 @@ template <class Machine> void TargetX86Base<Machine>::prelowerPhis() {
for (SizeT I = 0; I < Phi->getSrcSize(); ++I) { for (SizeT I = 0; I < Phi->getSrcSize(); ++I) {
Operand *Src = Phi->getSrc(I); Operand *Src = Phi->getSrc(I);
CfgNode *Label = Phi->getLabel(I); CfgNode *Label = Phi->getLabel(I);
if (llvm::isa<ConstantUndef>(Src)) Src = legalizeUndef(Src);
Src = Ctx->getConstantZero(Dest->getType());
PhiLo->addArgument(loOperand(Src), Label); PhiLo->addArgument(loOperand(Src), Label);
PhiHi->addArgument(hiOperand(Src), Label); PhiHi->addArgument(hiOperand(Src), Label);
} }
...@@ -4791,22 +4793,18 @@ void TargetX86Base<Machine>::lowerPhiAssignments( ...@@ -4791,22 +4793,18 @@ void TargetX86Base<Machine>::lowerPhiAssignments(
auto Assign = llvm::dyn_cast<InstAssign>(&I); auto Assign = llvm::dyn_cast<InstAssign>(&I);
Variable *Dest = Assign->getDest(); Variable *Dest = Assign->getDest();
// If the source operand is ConstantUndef, do not legalize it. // If the source operand is ConstantUndef, do not legalize it. In function
// In function test_split_undef_int_vec, the advanced phi // test_split_undef_int_vec, the advanced phi lowering process will find an
// lowering process will find an assignment of undefined // assignment of undefined vector. This vector, as the Src here, will crash
// vector. This vector, as the Src here, will crash if it // if it go through legalize(). legalize() will create a new variable with
// go through legalize(). legalize() will create new variable // makeVectorOfZeros(), but this new variable will be assigned a stack
// with makeVectorOfZeros(), but this new variable will be // slot. This will fail with pxor(Var, Var) because it is an illegal
// assigned a stack slot. This will fail the assertion in // instruction form. Note this failure is irrelevant to randomization or
// IceInstX8632.cpp:789, as XmmEmitterRegOp() complain: // pooling of constants. So, we do not call legalize() to add pool label
// Var->hasReg() fails. Note this failure is irrelevant to // for the src operands of phi assignment instructions. Instead, we
// randomization or pooling of constants. // manually add pool label for constant float and constant double values
// So, we do not call legalize() to add pool label for the // here. Note going through legalize() does not affect the testing results
// src operands of phi assignment instructions. // of SPEC2K and xtests.
// Instead, we manually add pool label for constant float and
// constant double values here.
// Note going through legalize() does not affect the testing
// results of SPEC2K and xtests.
Operand *Src = Assign->getSrc(0); Operand *Src = Assign->getSrc(0);
if (!llvm::isa<ConstantUndef>(Assign->getSrc(0))) { if (!llvm::isa<ConstantUndef>(Assign->getSrc(0))) {
Src = legalize(Src); Src = legalize(Src);
...@@ -5029,21 +5027,10 @@ Operand *TargetX86Base<Machine>::legalize(Operand *From, LegalMask Allowed, ...@@ -5029,21 +5027,10 @@ Operand *TargetX86Base<Machine>::legalize(Operand *From, LegalMask Allowed,
} }
if (auto *Const = llvm::dyn_cast<Constant>(From)) { if (auto *Const = llvm::dyn_cast<Constant>(From)) {
if (llvm::isa<ConstantUndef>(Const)) { if (llvm::isa<ConstantUndef>(Const)) {
// Lower undefs to zero. Another option is to lower undefs to an From = legalizeUndef(Const, RegNum);
// uninitialized register; however, using an uninitialized register
// results in less predictable code.
//
// If in the future the implementation is changed to lower undef
// values to uninitialized registers, a FakeDef will be needed:
// Context.insert(InstFakeDef::create(Func, Reg));
// This is in order to ensure that the live range of Reg is not
// overestimated. If the constant being lowered is a 64 bit value,
// then the result should be split and the lo and hi components will
// need to go in uninitialized registers.
if (isVectorType(Ty)) if (isVectorType(Ty))
return makeVectorOfZeros(Ty, RegNum); return From;
Const = Ctx->getConstantZero(Ty); Const = llvm::cast<Constant>(From);
From = Const;
} }
// There should be no constants of vector type (other than undef). // There should be no constants of vector type (other than undef).
assert(!isVectorType(Ty)); assert(!isVectorType(Ty));
...@@ -5105,6 +5092,29 @@ Variable *TargetX86Base<Machine>::legalizeToVar(Operand *From, int32_t RegNum) { ...@@ -5105,6 +5092,29 @@ Variable *TargetX86Base<Machine>::legalizeToVar(Operand *From, int32_t RegNum) {
return llvm::cast<Variable>(legalize(From, Legal_Reg, RegNum)); return llvm::cast<Variable>(legalize(From, Legal_Reg, RegNum));
} }
/// Legalize undef values to concrete values.
template <class Machine>
Operand *TargetX86Base<Machine>::legalizeUndef(Operand *From, int32_t RegNum) {
Type Ty = From->getType();
if (llvm::isa<ConstantUndef>(From)) {
// Lower undefs to zero. Another option is to lower undefs to an
// uninitialized register; however, using an uninitialized register
// results in less predictable code.
//
// If in the future the implementation is changed to lower undef
// values to uninitialized registers, a FakeDef will be needed:
// Context.insert(InstFakeDef::create(Func, Reg));
// This is in order to ensure that the live range of Reg is not
// overestimated. If the constant being lowered is a 64 bit value,
// then the result should be split and the lo and hi components will
// need to go in uninitialized registers.
if (isVectorType(Ty))
return makeVectorOfZeros(Ty, RegNum);
return Ctx->getConstantZero(Ty);
}
return From;
}
/// For the cmp instruction, if Src1 is an immediate, or known to be a /// For the cmp instruction, if Src1 is an immediate, or known to be a
/// physical register, we can allow Src0 to be a memory operand. /// physical register, we can allow Src0 to be a memory operand.
/// Otherwise, Src0 must be copied into a physical register. /// Otherwise, Src0 must be copied into a physical register.
...@@ -5117,7 +5127,7 @@ Operand *TargetX86Base<Machine>::legalizeSrc0ForCmp(Operand *Src0, ...@@ -5117,7 +5127,7 @@ Operand *TargetX86Base<Machine>::legalizeSrc0ForCmp(Operand *Src0,
bool IsSrc1ImmOrReg = false; bool IsSrc1ImmOrReg = false;
if (llvm::isa<Constant>(Src1)) { if (llvm::isa<Constant>(Src1)) {
IsSrc1ImmOrReg = true; IsSrc1ImmOrReg = true;
} else if (Variable *Var = llvm::dyn_cast<Variable>(Src1)) { } else if (auto *Var = llvm::dyn_cast<Variable>(Src1)) {
if (Var->hasReg()) if (Var->hasReg())
IsSrc1ImmOrReg = true; IsSrc1ImmOrReg = true;
} }
...@@ -5141,7 +5151,7 @@ TargetX86Base<Machine>::formMemoryOperand(Operand *Opnd, Type Ty, ...@@ -5141,7 +5151,7 @@ TargetX86Base<Machine>::formMemoryOperand(Operand *Opnd, Type Ty,
// the constant offset, we will work on the whole memory // the constant offset, we will work on the whole memory
// operand later as one entity later, this save one instruction. // operand later as one entity later, this save one instruction.
// By turning blinding and pooling off, we guarantee // By turning blinding and pooling off, we guarantee
// legalize(Offset) will return a constant*. // legalize(Offset) will return a Constant*.
{ {
BoolFlagSaver B(RandomizationPoolingPaused, true); BoolFlagSaver B(RandomizationPoolingPaused, true);
...@@ -5357,8 +5367,8 @@ TargetX86Base<Machine>::randomizeOrPoolImmediate( ...@@ -5357,8 +5367,8 @@ TargetX86Base<Machine>::randomizeOrPoolImmediate(
MemOperand->getShift(), MemOperand->getShift(),
MemOperand->getSegmentRegister()); MemOperand->getSegmentRegister());
// Label this memory operand as randomize, so we won't randomize it // Label this memory operand as randomized, so we won't randomize it
// again in case we call legalize() mutiple times on this memory // again in case we call legalize() multiple times on this memory
// operand. // operand.
NewMemOperand->setRandomized(true); NewMemOperand->setRandomized(true);
return NewMemOperand; return NewMemOperand;
......
...@@ -109,6 +109,17 @@ entry: ...@@ -109,6 +109,17 @@ entry:
; CHECK: cmovl ; CHECK: cmovl
; CHECK: cmovl ; CHECK: cmovl
define i64 @fold_cmp_select_64_undef(i64 %arg1) {
entry:
%arg1_trunc = trunc i64 %arg1 to i32
%cmp1 = icmp slt i32 undef, %arg1_trunc
%result = select i1 %cmp1, i64 %arg1, i64 undef
ret i64 %result
}
; CHECK-LABEL: fold_cmp_select_64_undef
; CHECK: cmp
; CHECK: cmovl
; CHECK: cmovl
; Cmp/select folding with intervening instructions. ; Cmp/select folding with intervening instructions.
define i32 @fold_cmp_select_intervening_insts(i32 %arg1, i32 %arg2) { define i32 @fold_cmp_select_intervening_insts(i32 %arg1, i32 %arg2) {
......
...@@ -771,6 +771,16 @@ entry: ...@@ -771,6 +771,16 @@ entry:
; need to be reshuffled via movs. The next test stores the result ; need to be reshuffled via movs. The next test stores the result
; somewhere, so in that case they do need to be mov'ed. ; somewhere, so in that case they do need to be mov'ed.
define i64 @test_atomic_cmpxchg_64_undef(i32 %iptr, i64 %desired) {
entry:
%ptr = inttoptr i32 %iptr to i64*
%old = call i64 @llvm.nacl.atomic.cmpxchg.i64(i64* %ptr, i64 undef,
i64 %desired, i32 6, i32 6)
ret i64 %old
}
; CHECK-LABEL: test_atomic_cmpxchg_64_undef
; CHECK: lock cmpxchg8b QWORD PTR [e{{.[^x]}}+0x0]
; Test a case where %old really does need to be copied out of edx:eax. ; Test a case where %old really does need to be copied out of edx:eax.
define void @test_atomic_cmpxchg_64_store(i32 %ret_iptr, i32 %iptr, i64 %expected, i64 %desired) { define void @test_atomic_cmpxchg_64_store(i32 %ret_iptr, i32 %iptr, i64 %expected, i64 %desired) {
entry: entry:
......
...@@ -416,6 +416,18 @@ entry: ...@@ -416,6 +416,18 @@ entry:
; ARM32: rev ; ARM32: rev
; ARM32: rev ; ARM32: rev
define i64 @test_bswap_64_undef() {
entry:
%r = call i64 @llvm.bswap.i64(i64 undef)
ret i64 %r
}
; CHECK-LABEL: test_bswap_64_undef
; CHECK: bswap e{{.*}}
; CHECK: bswap e{{.*}}
; ARM32-LABEL: test_bswap_64
; ARM32: rev
; ARM32: rev
define i32 @test_ctlz_32(i32 %x) { define i32 @test_ctlz_32(i32 %x) {
entry: entry:
%r = call i32 @llvm.ctlz.i32(i32 %x, i1 false) %r = call i32 @llvm.ctlz.i32(i32 %x, i1 false)
......
...@@ -130,3 +130,15 @@ entry: ...@@ -130,3 +130,15 @@ entry:
} }
; CHECK-LABEL: no_rmw_sub_i32_var ; CHECK-LABEL: no_rmw_sub_i32_var
; CHECK: sub e{{ax|bx|cx|dx|bp|di|si}},DWORD PTR [e{{ax|bx|cx|dx|bp|di|si}}] ; CHECK: sub e{{ax|bx|cx|dx|bp|di|si}},DWORD PTR [e{{ax|bx|cx|dx|bp|di|si}}]
define internal void @rmw_add_i64_undef(i32 %addr_arg) {
entry:
%addr = inttoptr i32 %addr_arg to i64*
%val = load i64, i64* %addr, align 1
%rmw = add i64 %val, undef
store i64 %rmw, i64* %addr, align 1
ret void
}
; CHECK-LABEL: rmw_add_i64_undef
; CHECK: add DWORD PTR [e{{ax|bx|cx|dx|bp|di|si}}],0x0
; CHECK: adc DWORD PTR [e{{ax|bx|cx|dx|bp|di|si}}+0x4],0x0
...@@ -147,3 +147,18 @@ sw.default: ...@@ -147,3 +147,18 @@ sw.default:
; ARM32-NEXT: beq [[ADDR:[0-9a-f]+]] ; ARM32-NEXT: beq [[ADDR:[0-9a-f]+]]
; ARM32-NEXT: b [[ADDR]] ; ARM32-NEXT: b [[ADDR]]
define i32 @testSwitchUndef64() {
entry:
switch i64 undef, label %sw.default [
i64 1, label %sw.default
]
sw.default:
ret i32 20
}
; CHECK-LABEL: testSwitchUndef64
; CHECK: mov {{.*}},0x0
; CHECK: mov {{.*}},0x0
; ARM32-LABEL: testSwitchUndef64
; ARM32: movw {{.*}}, #0
; ARM32: movw {{.*}}, #0
...@@ -25,6 +25,15 @@ entry: ...@@ -25,6 +25,15 @@ entry:
; CHECK: ret ; CHECK: ret
} }
define i32 @trunc_undef_i64() {
entry:
%ret = trunc i64 undef to i32
ret i32 %ret
; CHECK-LABEL: trunc_undef_i64
; CHECK: mov eax,0x0
; CHECK: ret
}
define float @undef_float() { define float @undef_float() {
entry: entry:
ret float undef ret float undef
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment