Commit b36ad9b4 by Jan Voung

Add a basic TargetARM32 skeleton which knows nothing.

Later commits will add more information, but this tests the conditional compilation and build setup. One way to do conditional compilation: determine this early, at LLVM configure/CMake time. Configure will fill in the template of SZTargets.def.in to get a SZTargets.def file. LLVM change: https://codereview.chromium.org/1084753002/ NaCl change: https://codereview.chromium.org/1082953002/ I suppose an alternative is to fill in the .def file via -D flags in CXXFLAGS. For conditional lit testing, pnacl-sz dumps the attributes when given the --build-atts so we just build on top of that. We do that instead of go the LLVM way of filling in a lit.site.cfg.in -> lit.site.cfg at configure/CMake time. BUG= https://code.google.com/p/nativeclient/issues/detail?id=4076 R=stichnot@chromium.org Review URL: https://codereview.chromium.org/1075363002
parent e7e9b024
......@@ -184,6 +184,7 @@ SRCS = \
IceRegAlloc.cpp \
IceRNG.cpp \
IceTargetLowering.cpp \
IceTargetLoweringARM32.cpp \
IceTargetLoweringX8632.cpp \
IceThreading.cpp \
IceTimerTree.cpp \
......
......@@ -47,9 +47,15 @@ struct {
// Validates values of build attributes. Prints them to Stream if
// Stream is non-null.
void ValidateAndGenerateBuildAttributes(const ClFlags &Flags, Ostream *Stream) {
if (Stream)
if (Stream) {
// List the requested target.
*Stream << Flags.getTargetArch() << "\n";
// List the supported targets.
#define SUBZERO_TARGET(TARGET) *Stream << "target_" #TARGET << "\n";
#include "llvm/Config/SZTargets.def"
}
for (size_t i = 0; i < llvm::array_lengthof(ConditionalBuildAttributes);
++i) {
switch (ConditionalBuildAttributes[i].FlagValue) {
......
//===- subzero/src/IceInstARM32.def - X-Macros for ARM32 insts --*- C++ -*-===//
//
// The Subzero Code Generator
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines properties of ARM32 instructions in the form of x-macros.
//
//===----------------------------------------------------------------------===//
#ifndef SUBZERO_SRC_ICEINSTARM32_DEF
#define SUBZERO_SRC_ICEINSTARM32_DEF
// NOTE: PC and SP are not considered isInt, to avoid register allocating.
// For the NaCl sandbox we also need to r9 for TLS, so just reserve always.
// TODO(jvoung): Allow r9 to be isInt when sandboxing is turned off
// (native mode).
#define REGARM32_GPR_TABLE \
/* val, encode, name, scratch, preserved, stackptr, frameptr, isInt, isFP */ \
X(Reg_r0, = 0, "r0", 1, 0, 0, 0, 1, 0) \
X(Reg_r1, = Reg_r0 + 1, "r1", 1, 0, 0, 0, 1, 0) \
X(Reg_r2, = Reg_r0 + 2, "r2", 1, 0, 0, 0, 1, 0) \
X(Reg_r3, = Reg_r0 + 3, "r3", 1, 0, 0, 0, 1, 0) \
X(Reg_r4, = Reg_r0 + 4, "r4", 0, 1, 0, 0, 1, 0) \
X(Reg_r5, = Reg_r0 + 5, "r5", 0, 1, 0, 0, 1, 0) \
X(Reg_r6, = Reg_r0 + 6, "r6", 0, 1, 0, 0, 1, 0) \
X(Reg_r7, = Reg_r0 + 7, "r7", 0, 1, 0, 0, 1, 0) \
X(Reg_r8, = Reg_r0 + 8, "r8", 0, 1, 0, 0, 1, 0) \
X(Reg_r9, = Reg_r0 + 9, "r9", 0, 1, 0, 0, 0, 0) \
X(Reg_r10, = Reg_r0 + 10, "r10", 0, 1, 0, 0, 1, 0) \
X(Reg_fp, = Reg_r0 + 11, "fp", 0, 1, 0, 1, 1, 0) \
X(Reg_ip, = Reg_r0 + 12, "ip", 1, 0, 0, 0, 1, 0) \
X(Reg_sp, = Reg_r0 + 13, "sp", 0, 1, 1, 0, 0, 0) \
X(Reg_lr, = Reg_r0 + 14, "lr", 0, 1, 0, 0, 1, 0) \
X(Reg_pc, = Reg_r0 + 15, "pc", 0, 1, 0, 0, 0, 0) \
//#define X(val, encode, name, scratch, preserved, stackptr, frameptr,
// isInt, isFP)
// TODO(jvoung): List FP registers and know S0 == D0 == Q0, etc.
// Be able to grab even registers, and the corresponding odd register
// for each even register.
// We also provide a combined table, so that there is a namespace where
// all of the registers are considered and have distinct numberings.
// This is in contrast to the above, where the "encode" is based on how
// the register numbers will be encoded in binaries and values can overlap.
#define REGARM32_TABLE \
/* val, encode, name, scratch, preserved, stackptr, frameptr, isInt, isFP */ \
REGARM32_GPR_TABLE
//#define X(val, encode, name, scratch, preserved, stackptr, frameptr,
// isInt, isFP)
#define REGARM32_TABLE_BOUNDS \
/* val, init */ \
X(Reg_GPR_First, = Reg_r0) \
X(Reg_GPR_Last, = Reg_pc)
//define X(val, init)
// TODO(jvoung): add condition code tables, etc.
#endif // SUBZERO_SRC_ICEINSTARM32_DEF
//===- subzero/src/IceInstARM32.h - ARM32 machine instructions --*- C++ -*-===//
//
// The Subzero Code Generator
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file declares the InstARM32 and OperandARM32 classes and
// their subclasses. This represents the machine instructions and
// operands used for ARM32 code selection.
//
//===----------------------------------------------------------------------===//
#ifndef SUBZERO_SRC_ICEINSTARM32_H
#define SUBZERO_SRC_ICEINSTARM32_H
#include "IceDefs.h"
namespace Ice {
class TargetARM32;
// Fill this in.
} // end of namespace Ice
#endif // SUBZERO_SRC_ICEINSTARM32_H
//===- subzero/src/IceInstX8632.h - Low-level x86 instructions --*- C++ -*-===//
//===- subzero/src/IceInstX8632.h - x86-32 machine instructions -*- C++ -*-===//
//
// The Subzero Code Generator
//
......
//===- subzero/src/IceRegistersARM32.h - Register information ---*- C++ -*-===//
//
// The Subzero Code Generator
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file declares the registers and their encodings for ARM32.
//
//===----------------------------------------------------------------------===//
#ifndef SUBZERO_SRC_ICEREGISTERSARM32_H
#define SUBZERO_SRC_ICEREGISTERSARM32_H
#include "IceDefs.h"
#include "IceInstARM32.def"
#include "IceTypes.h"
namespace Ice {
namespace RegARM32 {
// An enum of every register. The enum value may not match the encoding
// used to binary encode register operands in instructions.
enum AllRegisters {
#define X(val, encode, name, scratch, preserved, stackptr, frameptr, isInt, \
isFP) \
val,
REGARM32_TABLE
#undef X
Reg_NUM,
#define X(val, init) val init,
REGARM32_TABLE_BOUNDS
#undef X
};
// An enum of GPR Registers. The enum value does match the encoding used
// to binary encode register operands in instructions.
enum GPRRegister {
#define X(val, encode, name, scratch, preserved, stackptr, frameptr, isInt, \
isFP) \
Encoded_##val encode,
REGARM32_GPR_TABLE
#undef X
Encoded_Not_GPR = -1
};
// TODO(jvoung): Floating point and vector registers...
// Need to model overlap and difference in encoding too.
static inline GPRRegister getEncodedGPR(int32_t RegNum) {
assert(Reg_GPR_First <= RegNum && RegNum <= Reg_GPR_Last);
return GPRRegister(RegNum - Reg_GPR_First);
}
} // end of namespace RegARM32
} // end of namespace Ice
#endif // SUBZERO_SRC_ICEREGISTERSARM32_H
......@@ -15,12 +15,14 @@
//
//===----------------------------------------------------------------------===//
#include "assembler_arm32.h"
#include "assembler_ia32.h"
#include "IceCfg.h" // setError()
#include "IceCfgNode.h"
#include "IceOperand.h"
#include "IceRegAlloc.h"
#include "IceTargetLowering.h"
#include "IceTargetLoweringARM32.h"
#include "IceTargetLoweringX8632.h"
namespace Ice {
......@@ -62,34 +64,33 @@ Inst *LoweringContext::getLastInserted() const {
}
TargetLowering *TargetLowering::createLowering(TargetArch Target, Cfg *Func) {
// These statements can be #ifdef'd to specialize the code generator
// to a subset of the available targets. TODO: use CRTP.
if (Target == Target_X8632)
return TargetX8632::create(Func);
#if 0
if (Target == Target_X8664)
return IceTargetX8664::create(Func);
if (Target == Target_ARM32)
return IceTargetARM32::create(Func);
if (Target == Target_ARM64)
return IceTargetARM64::create(Func);
#endif
#define SUBZERO_TARGET(X) \
if (Target == Target_##X) \
return Target##X::create(Func);
#include "llvm/Config/SZTargets.def"
Func->setError("Unsupported target");
return nullptr;
}
TargetLowering::TargetLowering(Cfg *Func)
: Func(Func), Ctx(Func->getContext()), HasComputedFrame(false),
CallsReturnsTwice(false), StackAdjustment(0), Context(),
SnapshotStackAdjustment(0) {}
CallsReturnsTwice(false), StackAdjustment(0), NextLabelNumber(0),
Context(), SnapshotStackAdjustment(0) {}
std::unique_ptr<Assembler> TargetLowering::createAssembler(TargetArch Target,
Cfg *Func) {
// These statements can be #ifdef'd to specialize the assembler
// to a subset of the available targets. TODO: use CRTP.
// TODO(jvoung): use SZTargets.def (rename AssemblerX86 -> AssemblerX8632),
// and make the namespaces consistent.
if (Target == Target_X8632)
return std::unique_ptr<Assembler>(new x86::AssemblerX86());
Func->setError("Unsupported target");
if (Target == Target_ARM32)
return std::unique_ptr<Assembler>(new AssemblerARM32());
Func->setError("Unsupported target assembler");
return nullptr;
}
......@@ -229,22 +230,24 @@ void TargetLowering::regAlloc(RegAllocKind Kind) {
LinearScan.scan(RegMask, Ctx->getFlags().shouldRandomizeRegAlloc());
}
InstCall *TargetLowering::makeHelperCall(const IceString &Name, Variable *Dest,
SizeT MaxSrcs) {
const bool HasTailCall = false;
Constant *CallTarget = Ctx->getConstantExternSym(Name);
InstCall *Call =
InstCall::create(Func, MaxSrcs, Dest, CallTarget, HasTailCall);
return Call;
}
std::unique_ptr<TargetDataLowering>
TargetDataLowering::createLowering(GlobalContext *Ctx) {
// These statements can be #ifdef'd to specialize the code generator
// to a subset of the available targets. TODO: use CRTP.
TargetArch Target = Ctx->getFlags().getTargetArch();
if (Target == Target_X8632)
return std::unique_ptr<TargetDataLowering>(TargetDataX8632::create(Ctx));
#if 0
if (Target == Target_X8664)
return std::unique_ptr<TargetDataLowering>(TargetDataX8664::create(Ctx));
if (Target == Target_ARM32)
return std::unique_ptr<TargetDataLowering>(TargetDataARM32::create(Ctx));
if (Target == Target_ARM64)
return std::unique_ptr<TargetDataLowering>(TargetDataARM64::create(Ctx));
#endif
llvm_unreachable("Unsupported target");
#define SUBZERO_TARGET(X) \
if (Target == Target_##X) \
return std::unique_ptr<TargetDataLowering>(TargetData##X::create(Ctx));
#include "llvm/Config/SZTargets.def"
llvm_unreachable("Unsupported target data lowering");
return nullptr;
}
......
......@@ -95,6 +95,7 @@ class TargetLowering {
TargetLowering &operator=(const TargetLowering &) = delete;
public:
// TODO(jvoung): return a unique_ptr like the other factory functions.
static TargetLowering *createLowering(TargetArch Target, Cfg *Func);
static std::unique_ptr<Assembler> createAssembler(TargetArch Target,
Cfg *Func);
......@@ -171,6 +172,7 @@ public:
int32_t getStackAdjustment() const { return StackAdjustment; }
void updateStackAdjustment(int32_t Offset) { StackAdjustment += Offset; }
void resetStackAdjustment() { StackAdjustment = 0; }
SizeT makeNextLabelNumber() { return NextLabelNumber++; }
LoweringContext &getContext() { return Context; }
enum RegSet {
......@@ -241,6 +243,10 @@ protected:
// expansion before returning.
virtual void postLower() {}
// Make a call to an external helper function.
InstCall *makeHelperCall(const IceString &Name, Variable *Dest,
SizeT MaxSrcs);
Cfg *Func;
GlobalContext *Ctx;
bool HasComputedFrame;
......@@ -248,6 +254,7 @@ protected:
// StackAdjustment keeps track of the current stack offset from its
// natural location, as arguments are pushed for a function call.
int32_t StackAdjustment;
SizeT NextLabelNumber;
LoweringContext Context;
// Runtime helper function names
......
//===- subzero/src/IceTargetLoweringARM32.def - ARM32 X-macros --*- C++ -*-===//
//
// The Subzero Code Generator
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines certain patterns for lowering to ARM32 target
// instructions, in the form of x-macros.
//
//===----------------------------------------------------------------------===//
#ifndef SUBZERO_SRC_ICETARGETLOWERINGARM32_DEF
#define SUBZERO_SRC_ICETARGETLOWERINGARM32_DEF
// TODO(jvoung): Fill out comparison tables, etc. for 32/64-bit compares.
#endif // SUBZERO_SRC_ICETARGETLOWERINGARM32_DEF
//===- subzero/src/IceTargetLoweringARM32.h - ARM32 lowering ----*- C++ -*-===//
//
// The Subzero Code Generator
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file declares the TargetLoweringARM32 class, which implements the
// TargetLowering interface for the ARM 32-bit architecture.
//
//===----------------------------------------------------------------------===//
#ifndef SUBZERO_SRC_ICETARGETLOWERINGARM32_H
#define SUBZERO_SRC_ICETARGETLOWERINGARM32_H
#include "IceDefs.h"
#include "IceRegistersARM32.h"
#include "IceTargetLowering.h"
namespace Ice {
class TargetARM32 : public TargetLowering {
TargetARM32() = delete;
TargetARM32(const TargetARM32 &) = delete;
TargetARM32 &operator=(const TargetARM32 &) = delete;
public:
// TODO(jvoung): return a unique_ptr.
static TargetARM32 *create(Cfg *Func) { return new TargetARM32(Func); }
void translateOm1() override;
void translateO2() override;
bool doBranchOpt(Inst *I, const CfgNode *NextNode) override;
SizeT getNumRegisters() const override { return RegARM32::Reg_NUM; }
Variable *getPhysicalRegister(SizeT RegNum, Type Ty = IceType_void) override;
IceString getRegName(SizeT RegNum, Type Ty) const override;
llvm::SmallBitVector getRegisterSet(RegSetMask Include,
RegSetMask Exclude) const override;
const llvm::SmallBitVector &getRegisterSetForType(Type Ty) const override {
return TypeToRegisterSet[Ty];
}
bool hasFramePointer() const override { return UsesFramePointer; }
SizeT getFrameOrStackReg() const override {
return UsesFramePointer ? RegARM32::Reg_fp : RegARM32::Reg_sp;
}
size_t typeWidthInBytesOnStack(Type Ty) const override {
// Round up to the next multiple of 4 bytes. In particular, i1,
// i8, and i16 are rounded up to 4 bytes.
return (typeWidthInBytes(Ty) + 3) & ~3;
}
void emitVariable(const Variable *Var) const override;
void lowerArguments() override;
void addProlog(CfgNode *Node) override;
void addEpilog(CfgNode *Node) override;
protected:
explicit TargetARM32(Cfg *Func);
void postLower() override;
void lowerAlloca(const InstAlloca *Inst) override;
void lowerArithmetic(const InstArithmetic *Inst) override;
void lowerAssign(const InstAssign *Inst) override;
void lowerBr(const InstBr *Inst) override;
void lowerCall(const InstCall *Inst) override;
void lowerCast(const InstCast *Inst) override;
void lowerExtractElement(const InstExtractElement *Inst) override;
void lowerFcmp(const InstFcmp *Inst) override;
void lowerIcmp(const InstIcmp *Inst) override;
void lowerIntrinsicCall(const InstIntrinsicCall *Inst) override;
void lowerInsertElement(const InstInsertElement *Inst) override;
void lowerLoad(const InstLoad *Inst) override;
void lowerPhi(const InstPhi *Inst) override;
void lowerRet(const InstRet *Inst) override;
void lowerSelect(const InstSelect *Inst) override;
void lowerStore(const InstStore *Inst) override;
void lowerSwitch(const InstSwitch *Inst) override;
void lowerUnreachable(const InstUnreachable *Inst) override;
void prelowerPhis() override;
void lowerPhiAssignments(CfgNode *Node,
const AssignList &Assignments) override;
void doAddressOptLoad() override;
void doAddressOptStore() override;
void randomlyInsertNop(float Probability) override;
void makeRandomRegisterPermutation(
llvm::SmallVectorImpl<int32_t> &Permutation,
const llvm::SmallBitVector &ExcludeRegisters) const override;
static Type stackSlotType();
bool UsesFramePointer;
bool NeedsStackAlignment;
llvm::SmallBitVector TypeToRegisterSet[IceType_NUM];
llvm::SmallBitVector ScratchRegs;
llvm::SmallBitVector RegsUsed;
VarList PhysicalRegisters[IceType_NUM];
static IceString RegNames[];
private:
~TargetARM32() override {}
};
class TargetDataARM32 : public TargetDataLowering {
TargetDataARM32() = delete;
TargetDataARM32(const TargetDataARM32 &) = delete;
TargetDataARM32 &operator=(const TargetDataARM32 &) = delete;
public:
static TargetDataLowering *create(GlobalContext *Ctx) {
return new TargetDataARM32(Ctx);
}
void lowerGlobals(std::unique_ptr<VariableDeclarationList> Vars) const final;
void lowerConstants() const final;
protected:
explicit TargetDataARM32(GlobalContext *Ctx);
private:
void lowerGlobal(const VariableDeclaration &Var) const;
~TargetDataARM32() override {}
template <typename T> static void emitConstantPool(GlobalContext *Ctx);
};
} // end of namespace Ice
#endif // SUBZERO_SRC_ICETARGETLOWERINGARM32_H
......@@ -266,7 +266,7 @@ TargetX8632::TargetX8632(Cfg *Func)
Func->getContext()->getFlags().getTargetInstructionSet() -
TargetInstructionSet::X86InstructionSet_Begin)),
IsEbpBasedFrame(false), NeedsStackAlignment(false), FrameSizeLocals(0),
SpillAreaSizeBytes(0), NextLabelNumber(0) {
SpillAreaSizeBytes(0) {
static_assert((X86InstructionSet::End - X86InstructionSet::Begin) ==
(TargetInstructionSet::X86InstructionSet_End -
TargetInstructionSet::X86InstructionSet_Begin),
......
......@@ -57,7 +57,6 @@ public:
void lowerArguments() override;
void addProlog(CfgNode *Node) override;
void addEpilog(CfgNode *Node) override;
SizeT makeNextLabelNumber() { return NextLabelNumber++; }
// Ensure that a 64-bit Variable has been split into 2 32-bit
// Variables, creating them if necessary. This is needed for all
// I64 operations, and it is needed for pushing F64 arguments for
......@@ -156,15 +155,6 @@ protected:
OperandX8632Mem *FormMemoryOperand(Operand *Ptr, Type Ty);
Variable *makeReg(Type Ty, int32_t RegNum = Variable::NoRegister);
// Make a call to an external helper function.
InstCall *makeHelperCall(const IceString &Name, Variable *Dest,
SizeT MaxSrcs) {
const bool HasTailCall = false;
Constant *CallTarget = Ctx->getConstantExternSym(Name);
InstCall *Call =
InstCall::create(Func, MaxSrcs, Dest, CallTarget, HasTailCall);
return Call;
}
static Type stackSlotType();
Variable *copyToReg(Operand *Src, int32_t RegNum = Variable::NoRegister);
......@@ -501,7 +491,6 @@ protected:
llvm::SmallBitVector TypeToRegisterSet[IceType_NUM];
llvm::SmallBitVector ScratchRegs;
llvm::SmallBitVector RegsUsed;
SizeT NextLabelNumber;
VarList PhysicalRegisters[IceType_NUM];
static IceString RegNames[];
......
//===- subzero/src/assembler_arm32.h - Assembler for ARM32 ------*- C++ -*-===//
//
// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
//
// Modified by the Subzero authors.
//
//===----------------------------------------------------------------------===//
//
// The Subzero Code Generator
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the Assembler class for ARM32.
//
//===----------------------------------------------------------------------===//
#ifndef SUBZERO_SRC_ASSEMBLER_ARM32_H
#define SUBZERO_SRC_ASSEMBLER_ARM32_H
#include "IceDefs.h"
#include "IceFixups.h"
#include "assembler.h"
namespace Ice {
class AssemblerARM32 : public Assembler {
AssemblerARM32(const AssemblerARM32 &) = delete;
AssemblerARM32 &operator=(const AssemblerARM32 &) = delete;
public:
explicit AssemblerARM32(bool use_far_branches = false) : Assembler() {
// This mode is only needed and implemented for MIPS and ARM.
assert(!use_far_branches);
(void)use_far_branches;
}
~AssemblerARM32() override = default;
void alignFunction() override {
llvm::report_fatal_error("Not yet implemented.");
}
SizeT getBundleAlignLog2Bytes() const override { return 4; }
llvm::ArrayRef<uint8_t> getNonExecBundlePadding() const override {
llvm::report_fatal_error("Not yet implemented.");
}
void padWithNop(intptr_t Padding) override {
(void)Padding;
llvm::report_fatal_error("Not yet implemented.");
}
void BindCfgNodeLabel(SizeT NodeNumber) override {
(void)NodeNumber;
llvm::report_fatal_error("Not yet implemented.");
}
bool fixupIsPCRel(FixupKind Kind) const override {
(void)Kind;
llvm::report_fatal_error("Not yet implemented.");
}
};
} // end of namespace Ice
#endif // SUBZERO_SRC_ASSEMBLER_ARM32_H
//===- subzero/src/assembler_ia32.h - Assembler for x86-32 ------*- C++ -*-===//
//
// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
......@@ -18,8 +19,8 @@
//
//===----------------------------------------------------------------------===//
#ifndef SUBZERO_SRC_ASSEMBLER_IA32_H_
#define SUBZERO_SRC_ASSEMBLER_IA32_H_
#ifndef SUBZERO_SRC_ASSEMBLER_IA32_H
#define SUBZERO_SRC_ASSEMBLER_IA32_H
#include "IceConditionCodesX8632.h"
#include "IceDefs.h"
......@@ -882,4 +883,4 @@ inline void AssemblerX86::EmitOperandSizeOverride() { EmitUint8(0x66); }
} // end of namespace x86
} // end of namespace Ice
#endif // SUBZERO_SRC_ASSEMBLER_IA32_H_
#endif // SUBZERO_SRC_ASSEMBLER_IA32_H
......@@ -5,6 +5,13 @@
; RUN: %p2i -i %s --filetype=asm --args --verbose inst -threads=0 | FileCheck %s
; TODO(jvoung): Enable test when it does not llvm::report_fatal_error.
; The test runner wrappers don't handle error expected errors
; so we can't just "not" the command.
; RUIN: %if --need=target_ARM32 --command %p2i -i %s --filetype=asm \
; RUIN: --args --verbose inst -threads=0 --target arm32 \
; RUIN: | %if --need=target_ARM32 --command FileCheck %s --check-prefix ARM32
define i32 @Add(i32 %a, i32 %b) {
; CHECK: define i32 @Add
entry:
......
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