Commit 1ee34165 by Jan Voung

Bitcast of 64-bit immediates may need to split the immediate, not a var.

Currently, the integer immediate is legalized to a 64-bit integer register first, and then the lower/upper parts of that register are used for the bitcast. However, mov(64_bit_reg, imm) done by the legalization isn't legal. Similarly, trunc of 64-bit immediates need to take the lower half of the immediate, not legalize to a var first. This shifts the legalization code around. Other cases where immediates are illegal and legalized are idiv/div, but for those cases 64-bit operands are handled separately via a function call. The function call code properly splits up immediate arguments. BUG=none R=stichnot@chromium.org Review URL: https://codereview.chromium.org/348373005
parent 3bd9f1af
...@@ -1376,18 +1376,18 @@ void TargetX8632::lowerCast(const InstCast *Inst) { ...@@ -1376,18 +1376,18 @@ void TargetX8632::lowerCast(const InstCast *Inst) {
// a = cast(b) ==> t=cast(b); a=t; (link t->b, link a->t, no overlap) // a = cast(b) ==> t=cast(b); a=t; (link t->b, link a->t, no overlap)
InstCast::OpKind CastKind = Inst->getCastKind(); InstCast::OpKind CastKind = Inst->getCastKind();
Variable *Dest = Inst->getDest(); Variable *Dest = Inst->getDest();
// Src0RM is the source operand legalized to physical register or memory, but
// not immediate, since the relevant x86 native instructions don't allow an
// immediate operand. If the operand is an immediate, we could consider
// computing the strength-reduced result at translation time, but we're
// unlikely to see something like that in the bitcode that the optimizer
// wouldn't have already taken care of.
Operand *Src0RM = legalize(Inst->getSrc(0), Legal_Reg | Legal_Mem);
switch (CastKind) { switch (CastKind) {
default: default:
Func->setError("Cast type not supported"); Func->setError("Cast type not supported");
return; return;
case InstCast::Sext: case InstCast::Sext: {
// Src0RM is the source operand legalized to physical register or memory,
// but not immediate, since the relevant x86 native instructions don't
// allow an immediate operand. If the operand is an immediate, we could
// consider computing the strength-reduced result at translation time,
// but we're unlikely to see something like that in the bitcode that
// the optimizer wouldn't have already taken care of.
Operand *Src0RM = legalize(Inst->getSrc(0), Legal_Reg | Legal_Mem);
if (Dest->getType() == IceType_i64) { if (Dest->getType() == IceType_i64) {
// t1=movsx src; t2=t1; t2=sar t2, 31; dst.lo=t1; dst.hi=t2 // t1=movsx src; t2=t1; t2=sar t2, 31; dst.lo=t1; dst.hi=t2
Variable *DestLo = llvm::cast<Variable>(loOperand(Dest)); Variable *DestLo = llvm::cast<Variable>(loOperand(Dest));
...@@ -1412,7 +1412,9 @@ void TargetX8632::lowerCast(const InstCast *Inst) { ...@@ -1412,7 +1412,9 @@ void TargetX8632::lowerCast(const InstCast *Inst) {
_mov(Dest, T); _mov(Dest, T);
} }
break; break;
case InstCast::Zext: }
case InstCast::Zext: {
Operand *Src0RM = legalize(Inst->getSrc(0), Legal_Reg | Legal_Mem);
if (Dest->getType() == IceType_i64) { if (Dest->getType() == IceType_i64) {
// t1=movzx src; dst.lo=t1; dst.hi=0 // t1=movzx src; dst.lo=t1; dst.hi=0
Constant *Zero = Ctx->getConstantZero(IceType_i32); Constant *Zero = Ctx->getConstantZero(IceType_i32);
...@@ -1439,9 +1441,12 @@ void TargetX8632::lowerCast(const InstCast *Inst) { ...@@ -1439,9 +1441,12 @@ void TargetX8632::lowerCast(const InstCast *Inst) {
_mov(Dest, T); _mov(Dest, T);
} }
break; break;
}
case InstCast::Trunc: { case InstCast::Trunc: {
if (Src0RM->getType() == IceType_i64) Operand *Src0 = Inst->getSrc(0);
Src0RM = loOperand(Src0RM); if (Src0->getType() == IceType_i64)
Src0 = loOperand(Src0);
Operand *Src0RM = legalize(Src0, Legal_Reg | Legal_Mem);
// t1 = trunc Src0RM; Dest = t1 // t1 = trunc Src0RM; Dest = t1
Variable *T = NULL; Variable *T = NULL;
_mov(T, Src0RM); _mov(T, Src0RM);
...@@ -1450,6 +1455,7 @@ void TargetX8632::lowerCast(const InstCast *Inst) { ...@@ -1450,6 +1455,7 @@ void TargetX8632::lowerCast(const InstCast *Inst) {
} }
case InstCast::Fptrunc: case InstCast::Fptrunc:
case InstCast::Fpext: { case InstCast::Fpext: {
Operand *Src0RM = legalize(Inst->getSrc(0), Legal_Reg | Legal_Mem);
// t1 = cvt Src0RM; Dest = t1 // t1 = cvt Src0RM; Dest = t1
Variable *T = makeReg(Dest->getType()); Variable *T = makeReg(Dest->getType());
_cvt(T, Src0RM); _cvt(T, Src0RM);
...@@ -1473,6 +1479,7 @@ void TargetX8632::lowerCast(const InstCast *Inst) { ...@@ -1473,6 +1479,7 @@ void TargetX8632::lowerCast(const InstCast *Inst) {
Call->addArg(Inst->getSrc(0)); Call->addArg(Inst->getSrc(0));
lowerCall(Call); lowerCall(Call);
} else { } else {
Operand *Src0RM = legalize(Inst->getSrc(0), Legal_Reg | Legal_Mem);
// t1.i32 = cvt Src0RM; t2.dest_type = t1; Dest = t2.dest_type // t1.i32 = cvt Src0RM; t2.dest_type = t1; Dest = t2.dest_type
Variable *T_1 = makeReg(IceType_i32); Variable *T_1 = makeReg(IceType_i32);
Variable *T_2 = makeReg(Dest->getType()); Variable *T_2 = makeReg(Dest->getType());
...@@ -1488,7 +1495,7 @@ void TargetX8632::lowerCast(const InstCast *Inst) { ...@@ -1488,7 +1495,7 @@ void TargetX8632::lowerCast(const InstCast *Inst) {
split64(Dest); split64(Dest);
const SizeT MaxSrcs = 1; const SizeT MaxSrcs = 1;
Type DestType = Dest->getType(); Type DestType = Dest->getType();
Type SrcType = Src0RM->getType(); Type SrcType = Inst->getSrc(0)->getType();
IceString DstSubstring = (DestType == IceType_i64 ? "64" : "32"); IceString DstSubstring = (DestType == IceType_i64 ? "64" : "32");
IceString SrcSubstring = (SrcType == IceType_f32 ? "f" : "d"); IceString SrcSubstring = (SrcType == IceType_f32 ? "f" : "d");
// Possibilities are cvtftoui32, cvtdtoui32, cvtftoui64, cvtdtoui64 // Possibilities are cvtftoui32, cvtdtoui32, cvtftoui64, cvtdtoui64
...@@ -1499,6 +1506,7 @@ void TargetX8632::lowerCast(const InstCast *Inst) { ...@@ -1499,6 +1506,7 @@ void TargetX8632::lowerCast(const InstCast *Inst) {
lowerCall(Call); lowerCall(Call);
return; return;
} else { } else {
Operand *Src0RM = legalize(Inst->getSrc(0), Legal_Reg | Legal_Mem);
// t1.i32 = cvt Src0RM; t2.dest_type = t1; Dest = t2.dest_type // t1.i32 = cvt Src0RM; t2.dest_type = t1; Dest = t2.dest_type
Variable *T_1 = makeReg(IceType_i32); Variable *T_1 = makeReg(IceType_i32);
Variable *T_2 = makeReg(Dest->getType()); Variable *T_2 = makeReg(Dest->getType());
...@@ -1509,7 +1517,7 @@ void TargetX8632::lowerCast(const InstCast *Inst) { ...@@ -1509,7 +1517,7 @@ void TargetX8632::lowerCast(const InstCast *Inst) {
} }
break; break;
case InstCast::Sitofp: case InstCast::Sitofp:
if (Src0RM->getType() == IceType_i64) { if (Inst->getSrc(0)->getType() == IceType_i64) {
// Use a helper for x86-32. // Use a helper for x86-32.
const SizeT MaxSrcs = 1; const SizeT MaxSrcs = 1;
Type DestType = Dest->getType(); Type DestType = Dest->getType();
...@@ -1520,6 +1528,7 @@ void TargetX8632::lowerCast(const InstCast *Inst) { ...@@ -1520,6 +1528,7 @@ void TargetX8632::lowerCast(const InstCast *Inst) {
lowerCall(Call); lowerCall(Call);
return; return;
} else { } else {
Operand *Src0RM = legalize(Inst->getSrc(0), Legal_Reg | Legal_Mem);
// Sign-extend the operand. // Sign-extend the operand.
// t1.i32 = movsx Src0RM; t2 = Cvt t1.i32; Dest = t2 // t1.i32 = movsx Src0RM; t2 = Cvt t1.i32; Dest = t2
Variable *T_1 = makeReg(IceType_i32); Variable *T_1 = makeReg(IceType_i32);
...@@ -1532,22 +1541,24 @@ void TargetX8632::lowerCast(const InstCast *Inst) { ...@@ -1532,22 +1541,24 @@ void TargetX8632::lowerCast(const InstCast *Inst) {
_mov(Dest, T_2); _mov(Dest, T_2);
} }
break; break;
case InstCast::Uitofp: case InstCast::Uitofp: {
if (Src0RM->getType() == IceType_i64 || Src0RM->getType() == IceType_i32) { Operand *Src0 = Inst->getSrc(0);
if (Src0->getType() == IceType_i64 || Src0->getType() == IceType_i32) {
// Use a helper for x86-32 and x86-64. Also use a helper for // Use a helper for x86-32 and x86-64. Also use a helper for
// i32 on x86-32. // i32 on x86-32.
const SizeT MaxSrcs = 1; const SizeT MaxSrcs = 1;
Type DestType = Dest->getType(); Type DestType = Dest->getType();
IceString SrcSubstring = (Src0RM->getType() == IceType_i64 ? "64" : "32"); IceString SrcSubstring = (Src0->getType() == IceType_i64 ? "64" : "32");
IceString DstSubstring = (DestType == IceType_f32 ? "f" : "d"); IceString DstSubstring = (DestType == IceType_f32 ? "f" : "d");
// Possibilities are cvtui32tof, cvtui32tod, cvtui64tof, cvtui64tod // Possibilities are cvtui32tof, cvtui32tod, cvtui64tof, cvtui64tod
IceString TargetString = "cvtui" + SrcSubstring + "to" + DstSubstring; IceString TargetString = "cvtui" + SrcSubstring + "to" + DstSubstring;
// TODO: Call the correct compiler-rt helper function. // TODO: Call the correct compiler-rt helper function.
InstCall *Call = makeHelperCall(TargetString, Dest, MaxSrcs); InstCall *Call = makeHelperCall(TargetString, Dest, MaxSrcs);
Call->addArg(Inst->getSrc(0)); Call->addArg(Src0);
lowerCall(Call); lowerCall(Call);
return; return;
} else { } else {
Operand *Src0RM = legalize(Src0, Legal_Reg | Legal_Mem);
// Zero-extend the operand. // Zero-extend the operand.
// t1.i32 = movzx Src0RM; t2 = Cvt t1.i32; Dest = t2 // t1.i32 = movzx Src0RM; t2 = Cvt t1.i32; Dest = t2
Variable *T_1 = makeReg(IceType_i32); Variable *T_1 = makeReg(IceType_i32);
...@@ -1560,9 +1571,11 @@ void TargetX8632::lowerCast(const InstCast *Inst) { ...@@ -1560,9 +1571,11 @@ void TargetX8632::lowerCast(const InstCast *Inst) {
_mov(Dest, T_2); _mov(Dest, T_2);
} }
break; break;
case InstCast::Bitcast: }
if (Dest->getType() == Src0RM->getType()) { case InstCast::Bitcast: {
InstAssign *Assign = InstAssign::create(Func, Dest, Src0RM); Operand *Src0 = Inst->getSrc(0);
if (Dest->getType() == Src0->getType()) {
InstAssign *Assign = InstAssign::create(Func, Dest, Src0);
lowerAssign(Assign); lowerAssign(Assign);
return; return;
} }
...@@ -1571,6 +1584,7 @@ void TargetX8632::lowerCast(const InstCast *Inst) { ...@@ -1571,6 +1584,7 @@ void TargetX8632::lowerCast(const InstCast *Inst) {
llvm_unreachable("Unexpected Bitcast dest type"); llvm_unreachable("Unexpected Bitcast dest type");
case IceType_i32: case IceType_i32:
case IceType_f32: { case IceType_f32: {
Operand *Src0RM = legalize(Src0, Legal_Reg | Legal_Mem);
Type DestType = Dest->getType(); Type DestType = Dest->getType();
Type SrcType = Src0RM->getType(); Type SrcType = Src0RM->getType();
assert((DestType == IceType_i32 && SrcType == IceType_f32) || assert((DestType == IceType_i32 && SrcType == IceType_f32) ||
...@@ -1590,6 +1604,7 @@ void TargetX8632::lowerCast(const InstCast *Inst) { ...@@ -1590,6 +1604,7 @@ void TargetX8632::lowerCast(const InstCast *Inst) {
_mov(Dest, Spill); _mov(Dest, Spill);
} break; } break;
case IceType_i64: { case IceType_i64: {
Operand *Src0RM = legalize(Src0, Legal_Reg | Legal_Mem);
assert(Src0RM->getType() == IceType_f64); assert(Src0RM->getType() == IceType_f64);
// a.i64 = bitcast b.f64 ==> // a.i64 = bitcast b.f64 ==>
// s.f64 = spill b.f64 // s.f64 = spill b.f64
...@@ -1617,11 +1632,12 @@ void TargetX8632::lowerCast(const InstCast *Inst) { ...@@ -1617,11 +1632,12 @@ void TargetX8632::lowerCast(const InstCast *Inst) {
_mov(DestHi, T_Hi); _mov(DestHi, T_Hi);
} break; } break;
case IceType_f64: { case IceType_f64: {
assert(Src0RM->getType() == IceType_i64); Src0 = legalize(Src0);
assert(Src0->getType() == IceType_i64);
// a.f64 = bitcast b.i64 ==> // a.f64 = bitcast b.i64 ==>
// t_lo.i32 = b_lo.i32 // t_lo.i32 = b_lo.i32
// FakeDef(s.f64)
// lo(s.f64) = t_lo.i32 // lo(s.f64) = t_lo.i32
// FakeUse(s.f64)
// t_hi.i32 = b_hi.i32 // t_hi.i32 = b_hi.i32
// hi(s.f64) = t_hi.i32 // hi(s.f64) = t_hi.i32
// a.f64 = s.f64 // a.f64 = s.f64
...@@ -1629,22 +1645,25 @@ void TargetX8632::lowerCast(const InstCast *Inst) { ...@@ -1629,22 +1645,25 @@ void TargetX8632::lowerCast(const InstCast *Inst) {
Spill->setWeight(RegWeight::Zero); Spill->setWeight(RegWeight::Zero);
Spill->setPreferredRegister(Dest, true); Spill->setPreferredRegister(Dest, true);
Context.insert(InstFakeDef::create(Func, Spill));
Variable *T_Lo = NULL, *T_Hi = NULL; Variable *T_Lo = NULL, *T_Hi = NULL;
VariableSplit *SpillLo = VariableSplit *SpillLo =
VariableSplit::create(Func, Spill, VariableSplit::Low); VariableSplit::create(Func, Spill, VariableSplit::Low);
VariableSplit *SpillHi = VariableSplit *SpillHi =
VariableSplit::create(Func, Spill, VariableSplit::High); VariableSplit::create(Func, Spill, VariableSplit::High);
_mov(T_Lo, loOperand(Src0RM)); _mov(T_Lo, loOperand(Src0));
// Technically, the Spill is defined after the _store happens, but
// SpillLo is considered a "use" of Spill so define Spill before it
// is used.
Context.insert(InstFakeDef::create(Func, Spill));
_store(T_Lo, SpillLo); _store(T_Lo, SpillLo);
_mov(T_Hi, hiOperand(Src0RM)); _mov(T_Hi, hiOperand(Src0));
_store(T_Hi, SpillHi); _store(T_Hi, SpillHi);
_mov(Dest, Spill); _mov(Dest, Spill);
} break; } break;
} }
break; break;
} }
}
} }
void TargetX8632::lowerFcmp(const InstFcmp *Inst) { void TargetX8632::lowerFcmp(const InstFcmp *Inst) {
...@@ -2312,6 +2331,8 @@ Variable *TargetX8632::legalizeToVar(Operand *From, bool AllowOverlap, ...@@ -2312,6 +2331,8 @@ Variable *TargetX8632::legalizeToVar(Operand *From, bool AllowOverlap,
} }
Variable *TargetX8632::makeReg(Type Type, int32_t RegNum) { Variable *TargetX8632::makeReg(Type Type, int32_t RegNum) {
// There aren't any 64-bit integer registers for x86-32.
assert(Type != IceType_i64);
Variable *Reg = Func->makeVariable(Type, Context.getNode()); Variable *Reg = Func->makeVariable(Type, Context.getNode());
if (RegNum == Variable::NoRegister) if (RegNum == Variable::NoRegister)
Reg->setWeightInfinite(); Reg->setWeightInfinite();
......
...@@ -230,6 +230,23 @@ entry: ...@@ -230,6 +230,23 @@ entry:
; OPTM1: call __divdi3 ; OPTM1: call __divdi3
; OPTM1: ret ; OPTM1: ret
define internal i64 @div64BitSignedConst(i64 %a) {
entry:
%div = sdiv i64 %a, 12345678901234
ret i64 %div
}
; CHECK-LABEL: div64BitSignedConst:
; CHECK: push 2874
; CHECK: push 1942892530
; CHECK: call __divdi3
; CHECK: ret
;
; OPTM1-LABEL: div64BitSignedConst:
; OPTM1: push 2874
; OPTM1: push 1942892530
; OPTM1: call __divdi3
; OPTM1: ret
define internal i64 @div64BitUnsigned(i64 %a, i64 %b) { define internal i64 @div64BitUnsigned(i64 %a, i64 %b) {
entry: entry:
%div = udiv i64 %a, %b %div = udiv i64 %a, %b
...@@ -462,6 +479,31 @@ entry: ...@@ -462,6 +479,31 @@ entry:
; OPTM1: movsx eax, ; OPTM1: movsx eax,
; OPTM1: ret ; OPTM1: ret
define internal i32 @trunc64To32SignedConst() {
entry:
%conv = trunc i64 12345678901234 to i32
ret i32 %conv
}
; CHECK-LABEL: trunc64To32SignedConst
; CHECK: mov eax, 1942892530
;
; OPTM1-LABEL: trunc64To32SignedConst
; OPTM1: mov eax, 1942892530
define internal i32 @trunc64To16SignedConst() {
entry:
%conv = trunc i64 12345678901234 to i16
%conv.ret_ext = sext i16 %conv to i32
ret i32 %conv.ret_ext
}
; CHECK-LABEL: trunc64To16SignedConst
; CHECK: mov eax, 1942892530
; CHECK: movsx eax, ax
;
; OPTM1-LABEL: trunc64To16SignedConst
; OPTM1: mov eax, 1942892530
; OPTM1: movsx eax,
define internal i32 @trunc64To32Unsigned(i64 %a) { define internal i32 @trunc64To32Unsigned(i64 %a) {
entry: entry:
%conv = trunc i64 %a to i32 %conv = trunc i64 %a to i32
......
...@@ -11,7 +11,7 @@ entry: ...@@ -11,7 +11,7 @@ entry:
%v0 = bitcast float %f to i32 %v0 = bitcast float %f to i32
ret i32 %v0 ret i32 %v0
} }
; CHECK-LABEL: cast_f2i
; CHECK: mov eax ; CHECK: mov eax
; CHECK: ret ; CHECK: ret
...@@ -20,7 +20,7 @@ entry: ...@@ -20,7 +20,7 @@ entry:
%v0 = bitcast i32 %i to float %v0 = bitcast i32 %i to float
ret float %v0 ret float %v0
} }
; CHECK-LABEL: cast_i2f
; CHECK: fld dword ptr ; CHECK: fld dword ptr
; CHECK: ret ; CHECK: ret
...@@ -29,7 +29,17 @@ entry: ...@@ -29,7 +29,17 @@ entry:
%v0 = bitcast double %d to i64 %v0 = bitcast double %d to i64
ret i64 %v0 ret i64 %v0
} }
; CHECK-LABEL: cast_d2ll
; CHECK: mov edx
; CHECK: ret
define internal i64 @cast_d2ll_const() {
entry:
%v0 = bitcast double 0x12345678901234 to i64
ret i64 %v0
}
; CHECK-LABEL: cast_d2ll_const
; CHECK: movsd xmm{{.*}}, {{.*}}L$double
; CHECK: mov edx ; CHECK: mov edx
; CHECK: ret ; CHECK: ret
...@@ -38,7 +48,18 @@ entry: ...@@ -38,7 +48,18 @@ entry:
%v0 = bitcast i64 %ll to double %v0 = bitcast i64 %ll to double
ret double %v0 ret double %v0
} }
; CHECK-LABEL: cast_ll2d
; CHECK: fld qword ptr
; CHECK: ret
define internal double @cast_ll2d_const() {
entry:
%v0 = bitcast i64 12345678901234 to double
ret double %v0
}
; CHECK-LABEL: cast_ll2d_const
; CHECK: mov {{.*}}, 1942892530
; CHECK: mov {{.*}}, 2874
; CHECK: fld qword ptr ; CHECK: fld qword ptr
; CHECK: ret ; CHECK: ret
......
...@@ -405,6 +405,17 @@ entry: ...@@ -405,6 +405,17 @@ entry:
; CHECK: call cvtui64tof ; CHECK: call cvtui64tof
; CHECK: fstp ; CHECK: fstp
define internal double @unsigned64ToDoubleConst() {
entry:
%conv = uitofp i64 12345678901234 to double
ret double %conv
}
; CHECK-LABEL: unsigned64ToDouble
; CHECK: push 2874
; CHECK: push 1942892530
; CHECK: call cvtui64tod
; CHECK: fstp
define internal double @signed32ToDouble(i32 %a) { define internal double @signed32ToDouble(i32 %a) {
entry: entry:
%conv = sitofp i32 %a to double %conv = sitofp i32 %a to double
......
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