Mark setjmp as "returns twice" and turn off SimpleCoalescing when called.
BUG=none
R=stichnot@chromium.org
Review URL: https://codereview.chromium.org/567553003
diff --git a/src/IceIntrinsics.cpp b/src/IceIntrinsics.cpp
index 5b6ceac..e941ff9 100644
--- a/src/IceIntrinsics.cpp
+++ b/src/IceIntrinsics.cpp
@@ -24,39 +24,49 @@
namespace {
+void __attribute__((unused)) xIntrinsicInfoSizeCheck() {
+ STATIC_ASSERT(sizeof(Intrinsics::IntrinsicInfo) == 4);
+}
+
+#define INTRIN(ID, SE, RT) { Intrinsics::ID, Intrinsics::SE, Intrinsics::RT }
+
+// Build list of intrinsics with their attributes and expected prototypes.
+// List is sorted alphabetically.
const struct IceIntrinsicsEntry_ {
Intrinsics::FullIntrinsicInfo Info;
const char *IntrinsicName;
} IceIntrinsicsTable[] = {
+
#define AtomicCmpxchgInit(Overload, NameSuffix) \
{ \
{ \
- { Intrinsics::AtomicCmpxchg, true }, \
+ INTRIN(AtomicCmpxchg, SideEffects_T, ReturnsTwice_F), \
{ Overload, IceType_i32, Overload, Overload, IceType_i32, IceType_i32 }, \
- 6 \
- } \
- , "nacl.atomic.cmpxchg." NameSuffix \
+ 6 }, \
+ "nacl.atomic.cmpxchg." NameSuffix \
}
AtomicCmpxchgInit(IceType_i8, "i8"),
AtomicCmpxchgInit(IceType_i16, "i16"),
AtomicCmpxchgInit(IceType_i32, "i32"),
AtomicCmpxchgInit(IceType_i64, "i64"),
#undef AtomicCmpxchgInit
- { { { Intrinsics::AtomicFence, true }, { IceType_void, IceType_i32 }, 2 },
+
+ { { INTRIN(AtomicFence, SideEffects_T, ReturnsTwice_F),
+ { IceType_void, IceType_i32 }, 2 },
"nacl.atomic.fence" },
- { { { Intrinsics::AtomicFenceAll, true }, { IceType_void }, 1 },
+ { { INTRIN(AtomicFenceAll, SideEffects_T, ReturnsTwice_F),
+ { IceType_void }, 1 },
"nacl.atomic.fence.all" },
- { { { Intrinsics::AtomicIsLockFree, false },
+ { { INTRIN(AtomicIsLockFree, SideEffects_F, ReturnsTwice_F),
{ IceType_i1, IceType_i32, IceType_i32 }, 3 },
"nacl.atomic.is.lock.free" },
#define AtomicLoadInit(Overload, NameSuffix) \
{ \
{ \
- { Intrinsics::AtomicLoad, true } \
- , { Overload, IceType_i32, IceType_i32 }, 3 \
- } \
- , "nacl.atomic.load." NameSuffix \
+ INTRIN(AtomicLoad, SideEffects_T, ReturnsTwice_F), \
+ { Overload, IceType_i32, IceType_i32 }, 3 }, \
+ "nacl.atomic.load." NameSuffix \
}
AtomicLoadInit(IceType_i8, "i8"),
AtomicLoadInit(IceType_i16, "i16"),
@@ -67,7 +77,7 @@
#define AtomicRMWInit(Overload, NameSuffix) \
{ \
{ \
- { Intrinsics::AtomicRMW, true } \
+ INTRIN(AtomicRMW, SideEffects_T, ReturnsTwice_F) \
, { Overload, IceType_i32, IceType_i32, Overload, IceType_i32 }, 5 \
} \
, "nacl.atomic.rmw." NameSuffix \
@@ -81,7 +91,7 @@
#define AtomicStoreInit(Overload, NameSuffix) \
{ \
{ \
- { Intrinsics::AtomicStore, true } \
+ INTRIN(AtomicStore, SideEffects_T, ReturnsTwice_F) \
, { IceType_void, Overload, IceType_i32, IceType_i32 }, 4 \
} \
, "nacl.atomic.store." NameSuffix \
@@ -95,7 +105,7 @@
#define BswapInit(Overload, NameSuffix) \
{ \
{ \
- { Intrinsics::Bswap, false } \
+ INTRIN(Bswap, SideEffects_F, ReturnsTwice_F) \
, { Overload, Overload }, 2 \
} \
, "bswap." NameSuffix \
@@ -108,7 +118,7 @@
#define CtlzInit(Overload, NameSuffix) \
{ \
{ \
- { Intrinsics::Ctlz, false } \
+ INTRIN(Ctlz, SideEffects_F, ReturnsTwice_F) \
, { Overload, Overload, IceType_i1 }, 3 \
} \
, "ctlz." NameSuffix \
@@ -120,7 +130,7 @@
#define CtpopInit(Overload, NameSuffix) \
{ \
{ \
- { Intrinsics::Ctpop, false } \
+ INTRIN(Ctpop, SideEffects_F, ReturnsTwice_F) \
, { Overload, Overload }, 2 \
} \
, "ctpop." NameSuffix \
@@ -132,7 +142,7 @@
#define CttzInit(Overload, NameSuffix) \
{ \
{ \
- { Intrinsics::Cttz, false } \
+ INTRIN(Cttz, SideEffects_F, ReturnsTwice_F) \
, { Overload, Overload, IceType_i1 }, 3 \
} \
, "cttz." NameSuffix \
@@ -140,45 +150,57 @@
CttzInit(IceType_i32, "i32"),
CttzInit(IceType_i64, "i64"),
#undef CttzInit
- { { { Intrinsics::Longjmp, true },
+
+ { { INTRIN(Longjmp, SideEffects_T, ReturnsTwice_F),
{ IceType_void, IceType_i32, IceType_i32 }, 3 },
"nacl.longjmp" },
- { { { Intrinsics::Memcpy, true }, { IceType_void, IceType_i32, IceType_i32,
- IceType_i32, IceType_i32, IceType_i1 },
+ { { INTRIN(Memcpy, SideEffects_T, ReturnsTwice_F),
+ { IceType_void, IceType_i32, IceType_i32, IceType_i32, IceType_i32,
+ IceType_i1},
6 },
"memcpy.p0i8.p0i8.i32" },
- { { { Intrinsics::Memmove, true },
- { IceType_void, IceType_i32, IceType_i32,
- IceType_i32, IceType_i32, IceType_i1 },
+ { { INTRIN(Memmove, SideEffects_T, ReturnsTwice_F),
+ { IceType_void, IceType_i32, IceType_i32, IceType_i32, IceType_i32,
+ IceType_i1 },
6 },
"memmove.p0i8.p0i8.i32" },
- { { { Intrinsics::Memset, true }, { IceType_void, IceType_i32, IceType_i8,
- IceType_i32, IceType_i32, IceType_i1 },
+ { { INTRIN(Memset, SideEffects_T, ReturnsTwice_F),
+ { IceType_void, IceType_i32, IceType_i8, IceType_i32, IceType_i32,
+ IceType_i1 },
6 },
"memset.p0i8.i32" },
- { { { Intrinsics::NaClReadTP, false }, { IceType_i32 }, 1 },
+ { { INTRIN(NaClReadTP, SideEffects_F, ReturnsTwice_F),
+ { IceType_i32 }, 1 },
"nacl.read.tp" },
- { { { Intrinsics::Setjmp, true }, { IceType_i32, IceType_i32 }, 2 },
+ { { INTRIN(Setjmp, SideEffects_T, ReturnsTwice_T),
+ { IceType_i32, IceType_i32 }, 2 },
"nacl.setjmp" },
#define SqrtInit(Overload, NameSuffix) \
{ \
{ \
- { Intrinsics::Sqrt, false } \
- , { Overload, Overload }, 2 \
- } \
- , "sqrt." NameSuffix \
+ INTRIN(Sqrt, SideEffects_F, ReturnsTwice_F), \
+ { Overload, Overload }, 2 }, \
+ "sqrt." NameSuffix \
}
SqrtInit(IceType_f32, "f32"),
SqrtInit(IceType_f64, "f64"),
#undef SqrtInit
- { { { Intrinsics::Stacksave, true }, { IceType_i32 }, 1 }, "stacksave" },
- { { { Intrinsics::Stackrestore, true }, { IceType_void, IceType_i32 }, 2 },
+
+ { { INTRIN(Stacksave, SideEffects_T, ReturnsTwice_F),
+ { IceType_i32 }, 1 },
+ "stacksave" },
+ { { INTRIN(Stackrestore, SideEffects_T, ReturnsTwice_F),
+ { IceType_void, IceType_i32 }, 2 },
"stackrestore" },
- { { { Intrinsics::Trap, true }, { IceType_void }, 1 }, "trap" }
- };
+ { { INTRIN(Trap, SideEffects_T, ReturnsTwice_F),
+ { IceType_void }, 1 },
+ "trap" }
+};
const size_t IceIntrinsicsTableSize = llvm::array_lengthof(IceIntrinsicsTable);
+#undef INTRIN
+
} // end of anonymous namespace
Intrinsics::Intrinsics() {
diff --git a/src/IceIntrinsics.h b/src/IceIntrinsics.h
index b9c793a..d984b4c 100644
--- a/src/IceIntrinsics.h
+++ b/src/IceIntrinsics.h
@@ -88,15 +88,24 @@
static bool VerifyMemoryOrder(uint64_t Order);
+ enum SideEffects {
+ SideEffects_F=0,
+ SideEffects_T=1
+ };
+
+ enum ReturnsTwice {
+ ReturnsTwice_F=0,
+ ReturnsTwice_T=1
+ };
+
// Basic attributes related to each intrinsic, that are relevant to
- // code generation. We will want to have more attributes (e.g., Setjmp
- // returns twice and which affects stack coloring) once the lowering
- // cares about such attributes. Perhaps the attributes representation
- // can be shared with general function calls, though most functions
- // will be opaque.
+ // code generation. Perhaps the attributes representation can be shared
+ // with general function calls, but PNaCl currently strips all
+ // attributes from functions.
struct IntrinsicInfo {
- IntrinsicID ID : 31;
- bool HasSideEffects : 1;
+ enum IntrinsicID ID : 30;
+ enum SideEffects HasSideEffects : 1;
+ enum ReturnsTwice ReturnsTwice : 1;
};
// The complete set of information about an intrinsic.
diff --git a/src/IceTargetLowering.cpp b/src/IceTargetLowering.cpp
index 71788df..4ab6c63 100644
--- a/src/IceTargetLowering.cpp
+++ b/src/IceTargetLowering.cpp
@@ -171,9 +171,13 @@
case Inst::InsertElement:
lowerInsertElement(llvm::dyn_cast<InstInsertElement>(Inst));
break;
- case Inst::IntrinsicCall:
- lowerIntrinsicCall(llvm::dyn_cast<InstIntrinsicCall>(Inst));
+ case Inst::IntrinsicCall: {
+ InstIntrinsicCall *Call = llvm::dyn_cast<InstIntrinsicCall>(Inst);
+ if (Call->getIntrinsicInfo().ReturnsTwice)
+ setCallsReturnsTwice(true);
+ lowerIntrinsicCall(Call);
break;
+ }
case Inst::Load:
lowerLoad(llvm::dyn_cast<InstLoad>(Inst));
break;
diff --git a/src/IceTargetLowering.h b/src/IceTargetLowering.h
index a3410eb..b15c4f1 100644
--- a/src/IceTargetLowering.h
+++ b/src/IceTargetLowering.h
@@ -141,6 +141,12 @@
virtual llvm::ArrayRef<uint8_t> getNonExecBundlePadding() const = 0;
bool hasComputedFrame() const { return HasComputedFrame; }
bool shouldDoNopInsertion() const;
+ // Returns true if this function calls a function that has the
+ // "returns twice" attribute.
+ bool callsReturnsTwice() const { return CallsReturnsTwice; }
+ void setCallsReturnsTwice(bool RetTwice) {
+ CallsReturnsTwice = RetTwice;
+ }
int32_t getStackAdjustment() const { return StackAdjustment; }
void updateStackAdjustment(int32_t Offset) { StackAdjustment += Offset; }
void resetStackAdjustment() { StackAdjustment = 0; }
@@ -176,7 +182,7 @@
protected:
TargetLowering(Cfg *Func)
: Func(Func), Ctx(Func->getContext()), HasComputedFrame(false),
- StackAdjustment(0) {}
+ CallsReturnsTwice(false), StackAdjustment(0) {}
virtual void lowerAlloca(const InstAlloca *Inst) = 0;
virtual void lowerArithmetic(const InstArithmetic *Inst) = 0;
virtual void lowerAssign(const InstAssign *Inst) = 0;
@@ -210,6 +216,7 @@
Cfg *Func;
GlobalContext *Ctx;
bool HasComputedFrame;
+ bool CallsReturnsTwice;
// StackAdjustment keeps track of the current stack offset from its
// natural location, as arguments are pushed for a function call.
int32_t StackAdjustment;
diff --git a/src/IceTargetLoweringX8632.cpp b/src/IceTargetLoweringX8632.cpp
index c3a6e4d..abc6b41 100644
--- a/src/IceTargetLoweringX8632.cpp
+++ b/src/IceTargetLoweringX8632.cpp
@@ -647,9 +647,13 @@
// frames. If SimpleCoalescing is true, then each "global" variable
// without a register gets its own slot, but "local" variable slots
// are reused across basic blocks. E.g., if A and B are local to
- // block 1 and C is local to block 2, then C may share a slot with A
- // or B.
- const bool SimpleCoalescing = true;
+ // block 1 and C is local to block 2, then C may share a slot with A or B.
+ //
+ // We cannot coalesce stack slots if this function calls a "returns twice"
+ // function. In that case, basic blocks may be revisited, and variables
+ // local to those basic blocks are actually live until after the
+ // called function returns a second time.
+ const bool SimpleCoalescing = !callsReturnsTwice();
size_t InArgsSizeBytes = 0;
size_t PreservedRegsSizeBytes = 0;
SpillAreaSizeBytes = 0;