MC: make WinEH opcode an opaque value

This makes the opcode an opaque value (unsigned int) rather than the
enumeration.  This permits the use of target specific operands.

Split out the generic type into a MCWinEH header and add a supporting
MCWin64EH::Instruction to abstract out the selection of the opcode and
construction of the actual instruction.

llvm-svn: 213221
This commit is contained in:
Saleem Abdulrasool 2014-07-17 03:08:50 +00:00
parent 4fc91538e9
commit ab820860fa
4 changed files with 85 additions and 45 deletions

View File

@ -15,8 +15,8 @@
#ifndef LLVM_MC_MCWIN64EH_H
#define LLVM_MC_MCWIN64EH_H
#include "llvm/MC/MCWinEH.h"
#include "llvm/Support/Win64EH.h"
#include <cassert>
#include <vector>
namespace llvm {
@ -24,37 +24,35 @@ namespace llvm {
class MCStreamer;
class MCSymbol;
struct MCWin64EHInstruction {
typedef Win64EH::UnwindOpcodes OpType;
const OpType Operation;
const MCSymbol *Label;
const unsigned Offset;
const unsigned Register;
MCWin64EHInstruction(OpType Op, MCSymbol *L, unsigned Reg)
: Operation(Op), Label(L), Offset(0), Register(Reg) {
assert(Op == Win64EH::UOP_PushNonVol);
namespace Win64EH {
struct Instruction {
static WinEH::Instruction PushNonVol(MCSymbol *L, unsigned Reg) {
return WinEH::Instruction(Win64EH::UOP_PushNonVol, L, Reg, -1);
}
MCWin64EHInstruction(MCSymbol *L, unsigned Size)
: Operation(Size > 128 ? Win64EH::UOP_AllocLarge
: Win64EH::UOP_AllocSmall),
Label(L), Offset(Size), Register(-1) {}
MCWin64EHInstruction(OpType Op, MCSymbol *L, unsigned Reg, unsigned Off)
: Operation(Op), Label(L), Offset(Off), Register(Reg) {
assert(Op == Win64EH::UOP_SetFPReg ||
Op == Win64EH::UOP_SaveNonVol ||
Op == Win64EH::UOP_SaveNonVolBig ||
Op == Win64EH::UOP_SaveXMM128 ||
Op == Win64EH::UOP_SaveXMM128Big);
static WinEH::Instruction Alloc(MCSymbol *L, unsigned Size) {
return WinEH::Instruction(Size > 128 ? UOP_AllocLarge : UOP_AllocSmall, L,
-1, Size);
}
MCWin64EHInstruction(OpType Op, MCSymbol *L, bool Code)
: Operation(Op), Label(L), Offset(Code ? 1 : 0), Register(-1) {
assert(Op == Win64EH::UOP_PushMachFrame);
static WinEH::Instruction PushMachFrame(MCSymbol *L, bool Code) {
return WinEH::Instruction(UOP_PushMachFrame, L, -1, Code ? 1 : 0);
}
static WinEH::Instruction SaveNonVol(MCSymbol *L, unsigned Reg,
unsigned Offset) {
return WinEH::Instruction(Offset > 512 * 1024 - 8 ? UOP_SaveNonVolBig
: UOP_SaveNonVol,
L, Reg, Offset);
}
static WinEH::Instruction SaveXMM(MCSymbol *L, unsigned Reg,
unsigned Offset) {
return WinEH::Instruction(Offset > 512 * 1024 - 8 ? UOP_SaveXMM128Big
: UOP_SaveXMM128,
L, Reg, Offset);
}
static WinEH::Instruction SetFPReg(MCSymbol *L, unsigned Reg, unsigned Off) {
return WinEH::Instruction(UOP_SetFPReg, L, Reg, Off);
}
};
}
struct MCWinFrameInfo {
MCWinFrameInfo()
@ -72,7 +70,7 @@ struct MCWin64EHInstruction {
bool HandlesExceptions;
int LastFrameInst;
MCWinFrameInfo *ChainedParent;
std::vector<MCWin64EHInstruction> Instructions;
std::vector<WinEH::Instruction> Instructions;
};
class MCWin64EHUnwindEmitter {

View File

@ -0,0 +1,29 @@
//===- MCWinEH.h - Windows Unwinding Support --------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_MC_MCWINEH_H
#define LLVM_MC_MCWINEH_H
namespace llvm {
class MCSymbol;
namespace WinEH {
struct Instruction {
const MCSymbol *Label;
const unsigned Offset;
const unsigned Register;
const unsigned Operation;
Instruction(unsigned Op, MCSymbol *L, unsigned Reg, unsigned Off)
: Label(L), Offset(Off), Register(Reg), Operation(Op) {}
};
}
}
#endif

View File

@ -17,6 +17,7 @@
#include "llvm/MC/MCObjectFileInfo.h"
#include "llvm/MC/MCObjectWriter.h"
#include "llvm/MC/MCSymbol.h"
#include "llvm/MC/MCWin64EH.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/LEB128.h"
#include "llvm/Support/raw_ostream.h"
@ -479,9 +480,11 @@ void MCStreamer::EmitWinEHHandlerData() {
void MCStreamer::EmitWinCFIPushReg(unsigned Register) {
EnsureValidWinFrameInfo();
MCSymbol *Label = getContext().CreateTempSymbol();
MCWin64EHInstruction Inst(Win64EH::UOP_PushNonVol, Label, Register);
EmitLabel(Label);
WinEH::Instruction Inst = Win64EH::Instruction::PushNonVol(Label, Register);
CurrentWinFrameInfo->Instructions.push_back(Inst);
}
@ -493,9 +496,12 @@ void MCStreamer::EmitWinCFISetFrame(unsigned Register, unsigned Offset) {
report_fatal_error("Misaligned frame pointer offset!");
if (Offset > 240)
report_fatal_error("Frame offset must be less than or equal to 240!");
MCSymbol *Label = getContext().CreateTempSymbol();
MCWin64EHInstruction Inst(Win64EH::UOP_SetFPReg, Label, Register, Offset);
EmitLabel(Label);
WinEH::Instruction Inst =
Win64EH::Instruction::SetFPReg(Label, Register, Offset);
CurrentWinFrameInfo->LastFrameInst = CurrentWinFrameInfo->Instructions.size();
CurrentWinFrameInfo->Instructions.push_back(Inst);
}
@ -506,9 +512,11 @@ void MCStreamer::EmitWinCFIAllocStack(unsigned Size) {
report_fatal_error("Allocation size must be non-zero!");
if (Size & 7)
report_fatal_error("Misaligned stack allocation!");
MCSymbol *Label = getContext().CreateTempSymbol();
MCWin64EHInstruction Inst(Label, Size);
EmitLabel(Label);
WinEH::Instruction Inst = Win64EH::Instruction::Alloc(Label, Size);
CurrentWinFrameInfo->Instructions.push_back(Inst);
}
@ -516,11 +524,12 @@ void MCStreamer::EmitWinCFISaveReg(unsigned Register, unsigned Offset) {
EnsureValidWinFrameInfo();
if (Offset & 7)
report_fatal_error("Misaligned saved register offset!");
MCSymbol *Label = getContext().CreateTempSymbol();
MCWin64EHInstruction Inst(
Offset > 512*1024-8 ? Win64EH::UOP_SaveNonVolBig : Win64EH::UOP_SaveNonVol,
Label, Register, Offset);
EmitLabel(Label);
WinEH::Instruction Inst =
Win64EH::Instruction::SaveNonVol(Label, Register, Offset);
CurrentWinFrameInfo->Instructions.push_back(Inst);
}
@ -528,11 +537,12 @@ void MCStreamer::EmitWinCFISaveXMM(unsigned Register, unsigned Offset) {
EnsureValidWinFrameInfo();
if (Offset & 0x0F)
report_fatal_error("Misaligned saved vector register offset!");
MCSymbol *Label = getContext().CreateTempSymbol();
MCWin64EHInstruction Inst(
Offset > 512*1024-16 ? Win64EH::UOP_SaveXMM128Big : Win64EH::UOP_SaveXMM128,
Label, Register, Offset);
EmitLabel(Label);
WinEH::Instruction Inst =
Win64EH::Instruction::SaveXMM(Label, Register, Offset);
CurrentWinFrameInfo->Instructions.push_back(Inst);
}
@ -540,9 +550,11 @@ void MCStreamer::EmitWinCFIPushFrame(bool Code) {
EnsureValidWinFrameInfo();
if (CurrentWinFrameInfo->Instructions.size() > 0)
report_fatal_error("If present, PushMachFrame must be the first UOP");
MCSymbol *Label = getContext().CreateTempSymbol();
MCWin64EHInstruction Inst(Win64EH::UOP_PushMachFrame, Label, Code);
EmitLabel(Label);
WinEH::Instruction Inst = Win64EH::Instruction::PushMachFrame(Label, Code);
CurrentWinFrameInfo->Instructions.push_back(Inst);
}

View File

@ -15,15 +15,16 @@
#include "llvm/MC/MCSectionCOFF.h"
#include "llvm/MC/MCStreamer.h"
#include "llvm/MC/MCSymbol.h"
#include "llvm/Support/Win64EH.h"
namespace llvm {
// NOTE: All relocations generated here are 4-byte image-relative.
static uint8_t CountOfUnwindCodes(std::vector<MCWin64EHInstruction> &Insns) {
static uint8_t CountOfUnwindCodes(std::vector<WinEH::Instruction> &Insns) {
uint8_t Count = 0;
for (const auto &I : Insns) {
switch (I.Operation) {
switch (static_cast<Win64EH::UnwindOpcodes>(I.Operation)) {
case Win64EH::UOP_PushNonVol:
case Win64EH::UOP_AllocSmall:
case Win64EH::UOP_SetFPReg:
@ -56,11 +57,11 @@ static void EmitAbsDifference(MCStreamer &Streamer, const MCSymbol *LHS,
}
static void EmitUnwindCode(MCStreamer &streamer, MCSymbol *begin,
MCWin64EHInstruction &inst) {
WinEH::Instruction &inst) {
uint8_t b2;
uint16_t w;
b2 = (inst.Operation & 0x0F);
switch (inst.Operation) {
switch (static_cast<Win64EH::UnwindOpcodes>(inst.Operation)) {
case Win64EH::UOP_PushNonVol:
EmitAbsDifference(streamer, inst.Label, begin);
b2 |= (inst.Register & 0x0F) << 4;
@ -177,7 +178,7 @@ static void EmitUnwindInfo(MCStreamer &streamer, MCWinFrameInfo *info) {
uint8_t frame = 0;
if (info->LastFrameInst >= 0) {
MCWin64EHInstruction &frameInst = info->Instructions[info->LastFrameInst];
WinEH::Instruction &frameInst = info->Instructions[info->LastFrameInst];
assert(frameInst.Operation == Win64EH::UOP_SetFPReg);
frame = (frameInst.Register & 0x0F) | (frameInst.Offset & 0xF0);
}
@ -186,7 +187,7 @@ static void EmitUnwindInfo(MCStreamer &streamer, MCWinFrameInfo *info) {
// Emit unwind instructions (in reverse order).
uint8_t numInst = info->Instructions.size();
for (uint8_t c = 0; c < numInst; ++c) {
MCWin64EHInstruction inst = info->Instructions.back();
WinEH::Instruction inst = info->Instructions.back();
info->Instructions.pop_back();
EmitUnwindCode(streamer, info->Begin, inst);
}