Commit 44d53e1e by Jan Voung

Mark setjmp as "returns twice" and turn off SimpleCoalescing when called.

BUG=none R=stichnot@chromium.org Review URL: https://codereview.chromium.org/567553003
parent 47661568
......@@ -88,15 +88,24 @@ public:
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.
......
......@@ -171,9 +171,13 @@ void TargetLowering::lower() {
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;
......
......@@ -141,6 +141,12 @@ public:
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 @@ public:
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 @@ protected:
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;
......
......@@ -647,9 +647,13 @@ void TargetX8632::addProlog(CfgNode *Node) {
// 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;
......
; This file checks that SimpleCoalescing of local stack slots is not done
; when calling a function with the "returns twice" attribute.
; RUN: %llvm2ice -Om1 --verbose none %s \
; RUN: | llvm-mc -triple=i686-none-nacl -x86-asm-syntax=intel -filetype=obj \
; RUN: | llvm-objdump -d --symbolize -x86-asm-syntax=intel - | FileCheck %s
; RUN: %llvm2ice --verbose none %s | FileCheck --check-prefix=ERRORS %s
; Setjmp is a function with the "returns twice" attribute.
declare i32 @llvm.nacl.setjmp(i8*)
declare i32 @other(i32)
declare void @user(i32)
define i32 @call_returns_twice(i32 %iptr_jmpbuf, i32 %x) {
entry:
%local = add i32 %x, 12345
%jmpbuf = inttoptr i32 %iptr_jmpbuf to i8*
%y = call i32 @llvm.nacl.setjmp(i8* %jmpbuf)
call void @user(i32 %local)
%cmp = icmp eq i32 %y, 0
br i1 %cmp, label %Zero, label %NonZero
Zero:
%other_local = add i32 %x, 54321
call void @user(i32 %other_local)
ret i32 %other_local
NonZero:
ret i32 1
}
; CHECK-LABEL: call_returns_twice
; CHECK: add [[REG1:.*]], 12345
; CHECK: mov dword ptr [esp + [[OFF:.*]]], [[REG1]]
; CHECK: add [[REG2:.*]], 54321
; There should not be sharing of the stack slot.
; CHECK-NOT: mov dword ptr [esp + [[OFF]]], [[REG2]]
define i32 @no_call_returns_twice(i32 %iptr_jmpbuf, i32 %x) {
entry:
%local = add i32 %x, 12345
%y = call i32 @other(i32 %x)
call void @user(i32 %local)
%cmp = icmp eq i32 %y, 0
br i1 %cmp, label %Zero, label %NonZero
Zero:
%other_local = add i32 %x, 54321
call void @user(i32 %other_local)
ret i32 %other_local
NonZero:
ret i32 1
}
; CHECK-LABEL: no_call_returns_twice
; CHECK: add [[REG1:.*]], 12345
; CHECK: mov dword ptr [esp + [[OFF:.*]]], [[REG1]]
; CHECK: add [[REG2:.*]], 54321
; Now there should be sharing of the stack slot (OFF is the same).
; CHECK: mov dword ptr [esp + [[OFF]]], [[REG2]]
; ERRORS-NOT: ICE translation error
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